[英]Copying struct value to a interface{ } in golang
我想了解为什么当我将一个结构值复制到一个接口中时,它的行为就像它那样。 在此代码中,有人可以帮助我理解为什么当我将值从 mySlice 复制到 foo3 时,它的行为与其他副本不同吗?
package main
import (
"fmt"
"unsafe"
)
type SliceOfInt []int
// when passing a slice to a method you are passing this data. Lets prove it
type SliceHeader struct {
Data uintptr
Len int
Cap int
}
// Print the header of a slice. Its Data. Len and Cap
func GetHeaderOfSliceOfInt(s unsafe.Pointer) *SliceHeader {
// this header needs to point to &mySlice but compiler will not let us. we have to use unsafe pointers
var header *SliceHeader
pointerToMySlice := s
header = ((*SliceHeader)(pointerToMySlice))
return header
}
func main() {
// On go everything is passed by coping values. When you pass a slice to a function you are passing this:
// reference: https://stackoverflow.com/a/39993797/637142
/*
type SliceHeader struct {
Data uintptr
Len int
Cap int
}
*/
// create a new slice
var mySlice SliceOfInt = make([]int, 0)
mySlice = append(mySlice, 123456789) // append this number to mySlice
// now we have a slice with len:1 and capacity:1. Lets prove it
header := GetHeaderOfSliceOfInt(unsafe.Pointer(&mySlice))
fmt.Println(*header)
// this prints: {824635465728 1 1}
// this means that on memory address 824635465728 there is an array with cap:1 and len:1
// copy that header to someOtherSlice
someOtherSlice := mySlice
header = GetHeaderOfSliceOfInt(unsafe.Pointer(&someOtherSlice))
fmt.Println(*header)
// prints the same value {824635465728 1 1}
// anyways if I go to address 824635465728 on my computer I shoul dbe able to find integer 123456789
pointerToInteger := unsafe.Pointer((*header).Data)
var integerVal *int = ((*int)(pointerToInteger))
fmt.Println(*integerVal)
// if I copy like this, it will print the correct header {824635465728 1 1}
foo1 := mySlice
fmt.Println(*GetHeaderOfSliceOfInt(unsafe.Pointer(&foo1)))
// copy like this will also print the correct header {824635465728 1 1}
foo2 := foo1
fmt.Println(*GetHeaderOfSliceOfInt(unsafe.Pointer(&foo2)))
// If I copy like this it will print the incorrect header. Why?
var foo3 interface{} = mySlice
fmt.Println(*GetHeaderOfSliceOfInt(unsafe.Pointer(&foo3)))
// this last line prints {4746976 824635330392 0}
}
程序的output为:
{824635465728 1 1}
{824635465728 1 1}
123456789
{824635465728 1 1}
{824635465728 1 1}
{4746976 824635330392 0}
我知道如果我将 foo3 转换为: foo3.(SliceOfInt)
它会起作用。 但这是为什么呢?
接口类型,无论是否为空,本身就是一种类型。 它有自己的 memory 表示,是 Go 类型系统的合法成员。
接口值和包装在该接口中的值不是一回事。
变量foo1
和foo2
与mySlice
变量具有相同的类型和值。 但是变量foo3
有不同的类型,因此也有不同的值。 是的,动态类型和值与mySlice
相同,但static类型和值不同。
接口值在 memory 中未由与三字段SliceHeader
兼容的结构表示,因此尝试从接口值中取出切片 header 不仅在语义上是错误的。 相反,接口值由 2 字段结构表示(这就是为什么您尝试第三个字段是0
)。 第一个字段指向包装值的类型信息,第二个字段指向包装值的数据。
是这样的:
type iface struct {
typ uintptr
data uintptr
}
你可以通过这样做来测试它:
x := (*iface)(unsafe.Pointer(&foo3))
s := (*SliceHeader)(unsafe.Pointer(x.data))
fmt.Printf("%+v\n", x)
fmt.Printf("%+v\n", s)
https://go.dev/play/p/2KUgCU8h7O7
另外,请考虑阅读以下内容: https://research.swtch.com/interfaces 。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.