Interface 内存布局意味着[]T不能在Go中转换为[]接口,这是怎么回事?

Interface 内存布局意味着[]T不能在Go中转换为[]接口,这是怎么回事?,interface,go,language-design,duck-typing,memory-layout,Interface,Go,Language Design,Duck Typing,Memory Layout,所以我一直在读这两篇文章和这个答案 表示内存布局需要更改 说理解潜在的记忆使回答这个问题变得容易,而且 ,解释引擎盖下发生的事情 但就我的一生而言,我想不出一个理由,在接口的实现方面,为什么[]t不能转换为[]接口 那为什么呢 文章“尝试详述: 类型为[]接口{}的变量不是接口!它是一个元素类型恰好为接口{}的切片。但即便如此,也有人可能会说其含义是明确的 是吗?类型为[]接口{}的变量具有特定的内存布局,在编译时已知 每个接口{}占用两个字(一个字表示所包含的内容的类型,另一个字表示所包含的数

所以我一直在读这两篇文章和这个答案

表示内存布局需要更改

说理解潜在的记忆使回答这个问题变得容易,而且

,解释引擎盖下发生的事情

但就我的一生而言,我想不出一个理由,在接口的实现方面,为什么[]t不能转换为[]接口

那为什么呢

文章“尝试详述:

类型为
[]接口{}
的变量不是接口!它是一个元素类型恰好为
接口{}
的切片。但即便如此,也有人可能会说其含义是明确的

是吗?类型为
[]接口{}
的变量具有特定的内存布局,在编译时已知

每个
接口{}
占用两个字(一个字表示所包含的内容的类型,另一个字表示所包含的数据或指向它的指针)。因此,长度为N且类型为
[]接口{}
的切片由N*2个字长的数据块支持

另见“

这与支持类型为
[]MyType
且长度相同的切片的数据块不同。它的数据块将是
N*sizeof(MyType)
字长

结果是您无法将类型为
[]MyType
的对象快速分配给类型为
[]interface{}
的对象;它们背后的数据看起来完全不同

“”添加了一个很好的说明:

// 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!
文章“”试图详细说明:

类型为
[]接口{}
的变量不是接口!它是一个元素类型恰好为
接口{}
的切片。但即便如此,也有人可能会说其含义是明确的

是吗?类型为
[]接口{}
的变量具有特定的内存布局,在编译时已知

每个
接口{}
占用两个字(一个字表示所包含的内容的类型,另一个字表示所包含的数据或指向它的指针)。因此,长度为N且类型为
[]接口{}
的切片由N*2个字长的数据块支持

另见“

这与支持类型为
[]MyType
且长度相同的切片的数据块不同。它的数据块将是
N*sizeof(MyType)
字长

结果是您无法将类型为
[]MyType
的对象快速分配给类型为
[]interface{}
的对象;它们背后的数据看起来完全不同

“”添加了一个很好的说明:

// 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!
阅读博客文章,第节

接口类型的变量存储一对:分配给变量的具体值和该值的类型描述符。更准确地说,值是实现接口的底层具体数据项,类型描述该项的完整类型

因此,如果您的值为
[]T
T
)而
T
不是接口,那么这样一个片的元素只存储
T
类型的值,而不存储类型信息,它属于片类型

如果您有一个类型为
[]interface{}
的值,那么这样一个片的元素将保存这些值的具体值和类型描述符

因此
[]接口{}
中的元素比非接口
[]T
中的元素需要更多的信息(更多的内存)。如果这两个片占用的内存不一样,它们就不能以不同的方式“查看”(视为不同的类型)。从另一个生成一个需要额外的工作。

阅读博客文章,部分

接口类型的变量存储一对:分配给变量的具体值和该值的类型描述符。更准确地说,值是实现接口的底层具体数据项,类型描述该项的完整类型

因此,如果您的值为
[]T
T
)而
T
不是接口,那么这样一个片的元素只存储
T
类型的值,而不存储类型信息,它属于片类型

如果您有一个类型为
[]interface{}
的值,那么这样一个片的元素将保存这些值的具体值和类型描述符


因此
[]接口{}
中的元素比非接口
[]T
中的元素需要更多的信息(更多的内存)。如果这两个片占用的内存不一样,它们就不能以不同的方式“查看”(视为不同的类型)。从另一个生成一个需要额外的工作。

最后一个代码部分确定了它:它将在不接触反射的情况下破坏类型安全性+1@icza的确所以这不仅仅是关于内存分配。这也是因为在编译时,Go无法检测到
接口[0]
(这是一个
接口{}
=1
无效。如果Go有一些“通用”的方法来指定
[]接口{}
;)的类型就好了等等,我得到了最后一部分,它类似于数组的协方差,对吗?破坏类型安全性是因为现在可以将整数视为字符串,而不能这样处理。然而,关于N*sizeof(MyType)的部分——在这种情况下,MyType仍然有两个单词长,只有两个pointers@praks5432不,MyType不是两个单词长。只有
接口{}
有两个单词长(如答案中的图表所示)。@VonC但该图表表示一个通用接口否?还有两个指针。在接口{}的情况下,一个指向数据,一个指向基础类型。在其他接口中,一个指向方法表,一个指向数据??最后一个代码部分将其锁定:它将在不接触refle的情况下破坏类型安全性