gpt4 book ai didi

go - slice 中指针的行为

转载 作者:数据小太阳 更新时间:2023-10-29 03:32:53 25 4
gpt4 key购买 nike

从 slice 创建 slice 的行为是什么?当您像这样定义 slice 时:

s := []int{2, 3, 5, 7, 11, 13}

你想像这样修改你的 slice :
s = s[:3]
// s = [2 3 5]
s = s[:cap(s)]
// s = [2 3 5 7 11 13]

它实际上可以“正确扩展”您的 slice 。哪个不起作用:
s = s[2:]
// s = [5 7 11 13]
s = [:cap(s)]
// s = [5 7 11 13]

因此,在这种情况下,当您创建新 slice 时,您无法“保留”前两个元素。即使底层数组没有改变,你也不能改变指向该数组开头的指针,对吗?这是为什么?

最佳答案

正如@JimB 在评论中指出的那样,这是由于 slice 在 Go 中的运作方式。

从根本上说, slice 头是一个包含 3 个元素的结构:指向第一个元素的指针、当前数据的长度以及从“第一个元素”指针测量的底层数组的总容量(即使它只是一部分实际分配的底层数组)。它没有关于底层数组的其他信息。

当您通过 s[:x] 从末尾切断数据时,您正在创建一个新的 slice header ,它具有不同的长度字段,但具有相同的容量和第一个元素指针。因此,您可以再次将 slice 扩展到最大容量,因为运行时知道该内存已分配并且可以安全访问。

当您使用 s[x:] ,您正在创建一个新的 slice header ,它具有指向新第一个元素的不同初始指针和减少的容量,以及减少的长度。您不能“撤消”它以指向原始的第一个元素,因为除了该指针和容量字段之外, slice 结构没有关于原始 slice 或底层数组的信息。

例如,如果您制作 slice s := []int{2, 3, 5, 7, 11, 13} ,您的 slice header 可能包含:

ptr: 0x00000000
len: 6
cap: 6

如果您随后调用 s = s[:3] ,您的 slice header 将包含:
ptr: 0x00000000
len: 3
cap: 6

请注意,只有 len 发生了变化。如果您随后调用 s = s[:cap(s)] ,运行时看到容量可以支持那个 slice 操作,这意味着底层数组至少分配了那么多“槽”,并且没有问题地扩展 slice 。由于原始数据仍在那些“槽”中,您将得到与原始数组功能等效的内容:
ptr: 0x00000000
len: 6
cap: 6

但是,如果您调用 s = s[2:] ,您将得到以下信息:
ptr: 0x00000010
len: 4
cap: 4

注意除了长度变了,指针前进了16个字节(64位系统上两个 int的大小),容量字段也减少了,因为底层数组只有4"槽”相对于该指针分配。

现在,运行时除了那个 header 之外没有关于底层指针的其他信息!从该头文件,运行时无法知道原始底层数组的大小或它的原始起点在哪里,或者即使当前 slice 未从该原始起点开始。因此,尝试将 slice 重置回原始起点是不合法的,因为运行时无法验证该内存是否已分配且安全。这是一个有意的设计决定,因为 Go 专门设计为不允许在 C++ 程序中如此常见的不明智和高度错误的任意指针算法类型。

另外,您的电话是 s = s[:cap(s)]正在使用存储在 slice header 中的新(减少的)容量。虽然您的第一个这种性质的电话相当于 s = s[:6] ,因为这是原始 slice 的容量,所以调用现在等效于 s = s[:4] ,因为移动 slice 的指针也会减少后备数组的容量(因为容量是从该指针指向的元素而不是实际后备数组的第一个元素测量的)。

如果 Go 运行时将 slice 作为指针(指向支持数组中的绝对第一个元素)、长度、容量和偏移量进行跟踪,那么您想要的将是可能的。但是,它不会这样做。部分是因为这意味着 slice header 的大小增加了 33%(特别是为了尽可能轻量级),部分是因为,正如@JimB 指出的那样,该语言的开发人员认为额外的复杂性是不必要,因为如果您认为有必要,您可以轻松地自己保留原始 slice 标题的句柄。

关于go - slice 中指针的行为,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47817849/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com