簡體   English   中英

如何在 Go 中獲取切片的底層數組?

[英]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 時的情況。

對不起,解釋過度​​了,只是自己走過它,但有人可以向我解釋底層數組的底層發生了什么以及如何獲得對新數組的引用嗎?

首先,如果你還沒有,你應該閱讀這篇關於切片內部的官方博客文章 這應該清理一切。

現在要訪問底層數組,您可以使用reflectunsafe的組合。 特別是, 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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM