分析go中slice的奇怪现象

栏目: Go · 发布时间: 7年前

内容简介:片段一:片段二:可以看到,片段一和片段二中s1和s2输出不一致。

片段一:

s := []byte("")
s1 := append(s,'a')
s2 := append(s,'b')
fmt.Println(s1,"=====",s2) // [97] ===== [98]
fmt.Println(string(s1),"======",string(s2)) // a ====== b
复制代码

片段二:

s := []byte("")
s1 := append(s,'a')
s2 := append(s,'b')
fmt.Println(string(s1),"======",string(s2)) // b ====== b
复制代码

可以看到,片段一和片段二中s1和s2输出不一致。

问题分析

初看起来,感觉是 fmt.Println(s1,"=====",s2) 这句话导致了结果的不一样。

具体原因,且看下面分解。

对于片段二,结果都是 b ,这个似乎是因为 append 的时候,赋值给了一个新的变量,导致了s指向的底层数据虽然改变了,但是s记录的len还是不变的,所以第二次append的时候,就把第一次的值给覆盖了。所以才得出了都是 b 的结果。

对于问题二的解释,其实还少考虑了一个问题,那就是如果在append的时候,底层数组重新分配了,那么,就不会出现这个问题了。不信,看下面这个例子:

s := []int{5, 7, 9}
fmt.Printf("%d, %d, %p\n", len(s), cap(s), &s[0]) // 3, 3, 0xc000016240
x := append(s, 11)
fmt.Printf("%d, %d, %p\n", len(x), cap(x), &x[0]) // 4, 6, 0xc0000141e0
y := append(s, 12)
fmt.Printf("%d, %d, %p\n", len(y), cap(y), &y[0]) // 4, 6, 0xc000014210
fmt.Println(s, x, y) // [5 7 9] [5 7 9 11] [5 7 9 12]
复制代码

从上面例子可以看到,一开始s的len是3, cap也是3,在第一次append的时候,底层数组需要扩容,翻倍为6,所以x的len是4, cap是6,此时指向的底层数组地址已经不同了,第二个append同理。所以两次append,因为底层数据扩容的原因,两次append作用的地方是不同的,导致第二次没有覆盖第一次的数据。

通过上面的解释,我们知道了第一个片段出现的原因就是因为两次append都扩容了,所以没有出现覆盖的现象。而第二个片段没有出现扩容的情况,所以就出现了覆盖的情况。

那么为什么会这样呢,我们尝试打印一下,初始化s的cap,可以发现片段一中初始化s的cap为0,片段二为32。具体原因可以看下面的逃逸分析

逃逸分析

使用下面的命令进行分析。

go tool compile -m main.go
复制代码

片段一:

main.go:9:13: s1 escapes to heap
main.go:6:13: ([]byte)("") escapes to heap
main.go:9:17: "=====" escapes to heap
main.go:9:17: s2 escapes to heap
main.go:10:20: string(s1) escapes to heap
main.go:10:20: string(s1) escapes to heap
main.go:10:25: "======" escapes to heap
main.go:10:40: string(s2) escapes to heap
main.go:10:40: string(s2) escapes to heap
main.go:9:13: main ... argument does not escape
main.go:10:13: main ... argument does not escape
复制代码

可以看到 s1s2 由于Println,逃逸到了heap上,所以s一开始的cap是0.

片段二:

main.go:9:20: string(s1) escapes to heap
main.go:9:20: string(s1) escapes to heap
main.go:9:25: "======" escapes to heap
main.go:9:40: string(s2) escapes to heap
main.go:9:40: string(s2) escapes to heap
main.go:6:13: main ([]byte)("") does not escape
main.go:9:13: main ... argument does not escape
复制代码

可以看到 s1s2 没有逃逸,还是在栈上,所以s一开始的cap是32(默认).


以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

3D游戏设计与开发

3D游戏设计与开发

2011-9 / 28.00元

《3D游戏设计与开发》,本书共分为九章:第一章主要对计算机游戏设计和3D游戏引擎进行简单介绍;第二章介绍3D游戏开发基础和Torque引擎的各种对象;第三章详细讲解游戏编程的语言及其语法;第四章详细介绍了Torque引擎编辑器的应用;第五章至第六章介绍了3D游戏的环境、角色和物品的制作;第七章讲解如何实现游戏音效;第八章详细介绍3D网络游戏的创建方法;第九章讲解如何掌握3D资源导入Torque引擎......一起来看看 《3D游戏设计与开发》 这本书的介绍吧!

随机密码生成器
随机密码生成器

多种字符组合密码

Markdown 在线编辑器
Markdown 在线编辑器

Markdown 在线编辑器

正则表达式在线测试
正则表达式在线测试

正则表达式在线测试