我想了解為什么當我將結構值復制到介面時它的行為就像它一樣。在這段代碼中,有人可以幫助我理解為什么當我將值從 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}
}
程式的輸出是:
{824635465728 1 1}
{824635465728 1 1}
123456789
{824635465728 1 1}
{824635465728 1 1}
{4746976 824635330392 0}
編輯
我知道如果我將 foo3 轉換為:foo3.(SliceOfInt)它將起作用。但這是為什么呢?
uj5u.com熱心網友回復:
介面型別,無論是否為空,本身就是一種型別。它有自己的記憶體表示,并且是 Go 型別系統的合法成員。
介面值和封裝在該介面中的值不是一回事。
變數foo1和foo2具有與變數相同的型別和值mySlice。但是變數foo3具有不同的型別,因此也具有不同的值。是的,動態型別和值相同,mySlice但靜態型別和值不同。
介面值在記憶體中不是由與三欄位兼容的結構表示的SliceHeader,因此嘗試從介面值中取出切片標頭是錯誤的,不僅在語意上。相反,介面值由 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 。
轉載請註明出處,本文鏈接:https://www.uj5u.com/qukuanlian/462792.html
下一篇:C語言中指標的最佳實踐
