In the below code snippet, I'd like to understand what exactly gets stored in iPerson
when its contents are still uninitialized: just a value of 0-bytes? Or is it actually a pointer under the hood (and also initialized to 0-bytes of course)? In any case, what exactly happens at iPerson = person
?
If iPerson = person
makes a copy of person
, what happens then when an object implementing IPerson
but with a different size/memory footprint gets assigned to iPerson
? I understand iPerson
is a variable stored on the stack, so its size must be fixed. Does that mean that the heap is actually used under the hood, so iPerson
is actually implemented as a pointer, but assignments still copy the object, as demonstrated by the above code?
Here's the code:
type Person struct{ name string }
type IPerson interface{}
func main() {
var person Person = Person{"John"}
var iPerson IPerson
fmt.Println(person) // => John
fmt.Println(iPerson) // => <nil> ...so looks like a pointer
iPerson = person // ...this seems to be making a copy
fmt.Println(iPerson) // => John
person.name = "Mike"
fmt.Println(person) // => Mike
fmt.Println(iPerson) // => John ...so looks like it wasn't a pointer,
// or at least something was definitely copied
}
(This question is the result of me having second thoughts on the precise factual correctness of my answer to why runtime error on io.WriterString?. So I decided to try to do some investigation to understand how is it exactly that interface variables and assignments to them work in Go.)
EDIT: after having received a few useful answers, I'm still puzzled with this:
iPerson = person
iPerson = &person
—both are legal. However, to me, this raises the question of why the compiler allows such weak typing to occur? One implication of the above is this:
iPerson = &person
var person2 = iPerson.(Person) # panic: interface conversion: interface is *main.Person, not main.Person
whereas changing the first line fixes it:
iPerson = person
var person2 = iPerson.(Person) # OK
...so it's not possible to determine statically whether iPerson
holds a pointer or a value; and it seems that anything can assign either one to it at runtime with no errors raised. Why was such design decision made? What purpose does it serve? It definitely does not to fit within the "type safety" mindset.