栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 面试经验 > 面试问答

切片中指针的行为

面试问答 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

切片中指针的行为

正如@JimB在注释中指出的,这是由于slice在Go中的功能。

基本上,切片标头是一个包含3个元素的结构:一个指向第一个元素的指针,当前数据的长度以及 根据“第一个元素”指针测量
的基础数组的总容量(即使它只是一部分)实际分配的基础数组的大小)。它在基础数组上没有其他信息。

当通过从端部切断数据

s[:x]
,要创建具有不同长度字段的新切片标头,但 同样的
容量和第一元素的指针。因此,您可以再次将切片扩展到最大容量,因为运行时知道该内存已分配并且可以安全访问。

当使用时

s[x:]
,您将创建一个新的slice头,它具有指向新的第一个元素的不同初始指针,并具有减小的容量以及减小的长度。您不能“撤消”该操作以使其指向原始的第一个元素,因为切片结构除了指针和容量字段外,没有有关原始切片或基础数组的信息。

例如,如果您制作slice

s := []int{2, 3, 5, 7, 11, 13}
,则slice头可能包含:

ptr: 0x00000000len: 6cap: 6

如果您随后调用

s = s[:3]
,则切片头将包含:

ptr: 0x00000000len: 3cap: 6

注意只有len改变了。如果您随后调用

s =s[:cap(s)]
,则运行时将看到该容量可以支持该片操作,这意味着基础数组至少分配了那么多的“插槽”,并且可以毫无问题地扩展该片。由于原始数据仍位于这些“插槽”中,因此您将获得与原始数组在功能上等效的内容:

ptr: 0x00000000len: 6cap: 6

但是,如果您致电

s = s[2:]
,则会得到以下信息:

ptr: 0x00000010len: 4cap: 4

请注意,除了更改长度之外,指针还增加了16个字节(在

int
64位系统上为2 s
的大小),并且由于下面的数组仅分配了4个“插槽”,所以容量字段也已减小。相对于该指针。

现在,运行时 除了该标头之外没有关于基础指针的其他信息! 从该标头中,运行时 无法
知道原始基础数组的大小或原始起点的位置,甚至无法知道当前切片不是从该原始起点开始的。结果,尝试将片重置回原始起点是不合法的,因为运行时无法验证内存是否已分配且安全。这是一个有意的设计决策,因为Go专门设计为不允许使用C
++程序中常见的不良建议和高度笨拙的任意指针算法。

此外,您的呼叫

s = s[:cap(s)]
使用的是切片头中存储的 (减少的)容量。虽然您第一次进行此调用等效于
s =s[:6]
,因为这是原始切片的容量,但现在调用等效于
s =s[:4]
,因为移动切片的指针还减少了后备数组的容量(因为该容量是从所指向的元素测量的)指向该指针, 而不是 实际后备数组的第一个元素)。

如果Go运行时改为将切片作为指针(指向后备数组中的绝对第一个元素),长度,容量和 offset进行
跟踪,则可以实现所需的操作。但是,它不会这样做。部分原因是因为这将导致切片标头的大小增加33%(专门用于尽可能轻量级),部分原因是正如@JimB所指出的那样,该语言的开发人员决定增加额外的复杂性不必要,因为如果您认为有必要,可以轻松地自己处理原始切片标头。



转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/375449.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号