Go 代码是否为更新的切片报告不正确的底层数组?



我有以下代码(Go Playground 示例(它定义了一个切片(在内部这将创建一个数组并将切片的指针设置为内存中的数组位置(,然后向其附加一个新值......

s := []int{1, 2, 3, 4}
hdr := (*reflect.SliceHeader)(unsafe.Pointer(&s))
data := *(*[4]int)(unsafe.Pointer(hdr.Data))
fmt.Printf("slice:  %Tnt%#vntlen: %dntcap: %dn", s, s, len(s), cap(s))
fmt.Printf("hdr: %#vn", hdr)   // &reflect.SliceHeader{Data:0x40e020, Len:4, Cap:4}
fmt.Printf("data: %#vn", data) // [4]int{1, 2, 3, 4}
s = append(s, 5)
hdr = (*reflect.SliceHeader)(unsafe.Pointer(&s))
data = *(*[4]int)(unsafe.Pointer(hdr.Data))
fmt.Printf("slice:  %Tnt%#vntlen: %dntcap: %dn", s, s, len(s), cap(s))
fmt.Printf("hdr: %#vn", hdr)   // &reflect.SliceHeader{Data:0x45e020, Len:5, Cap:8}
fmt.Printf("data: %#vn", data) // [4]int{1, 2, 3, 4}

我对这段代码的问题是最后一行,它表明尽管附加一个新值会导致重新创建底层数组(因为它需要调整大小(,但 data 变量报告的值似乎显示原始数组内容(例如,它的长度为 4(而不是更新的内容。

即使我们从中提取Data字段的SliceHeader显示底层数组的长度具有预期的更新长度 5?

我在这里错过了什么。为什么最后一行不会打印类似 [8]int{1, 2, 3, 4, 5, 0, 0, 0} .

谢谢!

这是因为在追加之后,您使用更新的切片标题中的数据指针,但仍将数据指针转换为 *[4]int,即指向 length=4 的数组的指针。除了 4 之外,它还能有什么长度?

这样做是可以的,但您只能访问底层更大数组的前 4 个元素。改用[8]int

data2 := *(*[8]int)(unsafe.Pointer(hdr.Data))
fmt.Printf("data: %#vn", data2) // [8]int{1, 2, 3, 4, 5, 0, 0, 0}

这将输出(在Go Playground上尝试(:

data: [8]int{1, 2, 3, 4, 5, 0, 0, 0}