[英]How to get the underlying array of a slice in Go?
假設我有以下長度為 3 的整數數組:
nums := [3]int{1,2,3}
然后我抓住前兩個項目的切片
numSlice := nums[:2]
在這兩種情況下,對 numSlice 和 nums 調用cap
產生 3,而len
分別產生 2 和 3。
如果我然后附加到該切片( numSlice = append(numSlice, 10)
),則底層數組( nums
)現在是[1 2 10]
。 兩者的cap
保持為 3,因為切片的底層數組相同,切片的 len 現在為 3。
但是,如果我再次附加到該切片( numSlice = append(numSlice, 20)
),則切片的底層數組必須更改 - 我們看到這是當 numSlice 的cap
現在加倍而 len 現在為 4 時的情況。
對不起,解釋過度了,只是自己走過它,但有人可以向我解釋底層數組的底層發生了什么以及如何獲得對新數組的引用嗎?
首先,如果你還沒有,你應該閱讀這篇關於切片內部的官方博客文章 。 這應該清理一切。
現在要訪問底層數組,您可以使用reflect
和unsafe
的組合。 特別是, reflect.SliceHeader
包含一個Data
字段,其中包含指向切片底層數組的指針。
從不unsafe
包的文檔改編的示例:
s := []int{1, 2, 3, 4}
hdr := (*reflect.SliceHeader)(unsafe.Pointer(&s))
data := *(*[4]int)(unsafe.Pointer(hdr.Data))
就像一個提示,回答你的第二個問題。 從Go 1.17開始,你可以這樣做
(*[2]int)(numSlice)
package main
import (
"fmt"
)
func main() {
nums := [3]int{1, 2, 3}
numSlice := nums[:2]
underArr1 := (*[2]int)(numSlice)
fmt.Println(&underArr1[0]) //0xc000016018
numSlice = append(numSlice, 10)
underArr2 := (*[3]int)(numSlice)
fmt.Println(&underArr2[0]) //0xc000016018 - same
fmt.Println(nums) // [1 2 10]
numSlice = append(numSlice, 20)
underArr3 := (*[3]int)(numSlice)
fmt.Println(&underArr3[0]) //0xc000078030 - different
fmt.Println(cap(numSlice)) // 6
}
說實話,你不必轉換為數組指針來查看地址,我只是為了回答你的第二個問題。
該行為確實是您描述的方式。 當你追加10
,你的底層數組中仍然剩下一個字段(因為它的長度是 3,但你的 numSlice 是 2),即使它當前被3
占用,它也可以使用,並且3
被覆蓋10
.
當您附加20
,沒有剩余的字段,因此它會創建一個新的底層數組(很可能有 6 個字段長,兩倍大)並將原始數組中的所有數據復制到那里並將指針移動到該數組。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.