What about memory layout means that []T cannot be

2019-02-20 10:38发布

问题:

So I've been reading these two articles and this answer

Cannot convert []string to []interface {} says that the memory layout needs to be changed.

http://jordanorelli.com/post/32665860244/how-to-use-interfaces-in-go says that understanding the underlying memory makes answering this question easy, and

http://research.swtch.com/interfaces, explains what is going on under the hood.

But for the life of me I can't think of a reason, in terms of the implementation of interfaces as to why []T cannot be cast to []interface.

So Why?

回答1:

The article "InterfaceSlice" try to detail:

A variable with type []interface{} is not an interface! It is a slice whose element type happens to be interface{}. But even given this, one might say that the meaning is clear.

Well, is it? A variable with type []interface{} has a specific memory layout, known at compile time.

Each interface{} takes up two words (one word for the type of what is contained, the other word for either the contained data or a pointer to it). As a consequence, a slice with length N and with type []interface{} is backed by a chunk of data that is N*2 words long.

See also "what is the meaning of interface{} in golang?"

This is different than the chunk of data backing a slice with type []MyType and the same length. Its chunk of data will be N*sizeof(MyType) words long.

The result is that you cannot quickly assign something of type []MyType to something of type []interface{}; the data behind them just look different.

"why []string can not be converted to []interface{} in Go" adds a good illustration:

// imagine this is possible
var sliceOfInterface = []interface{}(sliceOfStrings)
// since it's array of interface{} now - we can do anything
// let's put integer into the first position
sliceOfInterface[0] = 1
// sliceOfStrings still points to the same array, and now "one" is replaced by 1
fmt.Println(strings.ToUpper(sliceOfStrings[0])) // BANG!


回答2:

Read the blog article The Laws of Reflection, section The representation of an interface.

A variable of interface type stores a pair: the concrete value assigned to the variable, and that value's type descriptor. To be more precise, the value is the underlying concrete data item that implements the interface and the type describes the full type of that item.

So if you have a value of []T (a slice of T) where T is not an interface, the elements of such a slice only stores values of type T, but it does not store the type information, it belongs to the slice type.

If you have a value of type []inteface{}, the elements of such a slice holds the concrete values and the type descriptors of those values.

So elements in a []interface{} require more info (more memory) than in a non-interface []T. And if the occupied memory of those 2 slices are not the same, they cannot be just "looked at" differently (looked at as a differnet type). Producing one from the other requires additional work.