Interface 内存布局意味着[]T不能在Go中转换为[]接口,这是怎么回事?
所以我一直在读这两篇文章和这个答案 表示内存布局需要更改 说理解潜在的记忆使回答这个问题变得容易,而且 ,解释引擎盖下发生的事情 但就我的一生而言,我想不出一个理由,在接口的实现方面,为什么[]t不能转换为[]接口 那为什么呢 文章“尝试详述: 类型为Interface 内存布局意味着[]T不能在Go中转换为[]接口,这是怎么回事?,interface,go,language-design,duck-typing,memory-layout,Interface,Go,Language Design,Duck Typing,Memory Layout,所以我一直在读这两篇文章和这个答案 表示内存布局需要更改 说理解潜在的记忆使回答这个问题变得容易,而且 ,解释引擎盖下发生的事情 但就我的一生而言,我想不出一个理由,在接口的实现方面,为什么[]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的情况下破坏类型安全性