繁体   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