你好,我是轩脉刃。这篇是关于go切片的一些问题和回答。

go的切片基本上是代码中使用最多的一种数据结构了,使用这种数据结构有哪些要注意的点,这个是非常必要了解的东西。基本上,以前写的一篇博客 https://www.cnblogs.com/yjf512/p/9531282.html 就说的很清楚了。这里再深挖一些。

问题:go的切片数据结构是什么样子的?

切片是有可能在编译器就被内联的,而如果在编译器没有被内联,进入运行期,就是直接使用SliceHeader数据结构。

type SliceHeader struct {
Data uintptr
Len int
Cap int
}

这三个字段分别表示指针,长度,容量。

问题:为什么在初始化slice的时候尽量补全cap

当我们要创建一个slice结构,并且往slice中append元素的时候,我们可能有两种写法来初始化这个slice。

方法1:

package main

import "fmt"

func main() {
arr := []int{}
arr = append(arr, 1,2,3,4, 5)
fmt.Println(arr)
}

方法2:

package main

import "fmt"

func main() {
arr := make([]int, 0, 5)
arr = append(arr, 1,2,3,4, 5)
fmt.Println(arr)
}

方法2相较于方法1,就只有一个区别:在初始化[]int slice的时候在make中设置了cap的长度,就是slice的大小。

这两种方法对应的功能和输出结果是没有任何差别的,但是实际运行的时候,方法2会比少运行了一个growslice的命令。

这个我们可以通过打印汇编码进行查看:

方法1:

方法2:

我们看到方法1中使用了growsslice方法,而方法2中是没有调用这个方法的。

这个growslice的作用就是扩充slice的容量大小。就好比是原先我们没有定制容量,系统给了我们一个能装两个鞋子的盒子,但是当我们装到第三个鞋子的时候,这个盒子就不够了,我们就要换一个盒子,而换这个盒子,我们势必还需要将原先的盒子里面的鞋子也拿出来放到新的盒子里面。所以这个growsslice的操作是一个比较复杂的操作,它的表现和复杂度会高于最基本的初始化make方法。对追求性能的程序来说,应该能避免尽量避免。

具体对growsslice函数具体实现同学有兴趣的可以参考源码src的 runtime/slice.go 。

当然,我们并不是每次都能在slice初始化的时候就能准确预估到最终的使用容量的。所以这里使用了一个“尽量”。明白是否设置slice容量的区别,我们在能预估容量的时候,请尽量使用方法2那种预估容量后的slice初始化方式。

问题:如果不设置cap,make slice的时候,创建的cap为多大?

如果不设置cap,不管是使用make,还是直接使用[]slice 进行初始化,编译器都会计算初始化所需的空间,使用最小化的cap进行初始化。

a := make([]int, 0)  // cap 为0
a := []int{1,2,3} // cap 为3

可以从ssa看出

问题:slice什么时候决定扩张?

之前写过一篇文章 https://www.cnblogs.com/yjf512/p/10714792.html 里面得出的结论就是slice在编译期就决定是否要调用growslice。

这个逻辑是正确的。

编译器在ssa的时候 对于append是会转换为 OAPPEND(cmd/compile/internal/typecheck/universe.go) 。而在 cmd/compile/internal/ssagen/ssa.go 中,对其进行判断。

目前还看不懂下面append下面的逻辑,不过基于这个注释,能了解到这里growslice的逻辑。比较扩容前后大小,如果原先cap小于扩容后需要cap,就growslice。

总结

琢磨了四个关于切片的问题:

问题:go的切片数据结构是什么样子的?

问题:为什么在初始化slice的时候尽量补全cap?

问题:如果不设置cap,make slice的时候,创建的cap为多大?

问题:slice什么时候决定扩张?

最新文章

  1. Java学习笔记之JNDI(六)
  2. Registration Code
  3. Java NIO教程 文件系统
  4. javascript之with的使用 弊端
  5. 解决使用IIS5.0配置的FTP服务器,客户端浏览器访问时无法获取目录列表的问题。
  6. Android中Google地图路径导航,使用mapfragment地图上画出线路(google map api v2)详解
  7. mac10.7安装xcode3.2.5和xcode4.2过程和方法
  8. 【POJ 2823 Sliding Window】 单调队列
  9. hdu_5883_The Best Path(欧拉路)
  10. Linux目录结构详解
  11. List迭代过滤操作注意点
  12. 12小时格式Xcode的-在一个“TimePicker”24 NSDate的设置
  13. mysql 两张表的数据设置主外健关联删除
  14. MySQL mysqldump 导入/导出 结构&数据&存储过程&函数&事件&触发器
  15. Spring Boot - 基础 POM 文件
  16. HashMap和HashTable区别【转载】
  17. Spring MVC 3 表单中文提交post请求和get请求乱码问题的解决方法
  18. ubuntu 12.04下 eclipse的安装
  19. 亿级Web系统搭建:单机到分布式集群【转】
  20. Unreal Engine 4 反射机制的实现

热门文章

  1. 点击下拉选择触发事件【c#】
  2. 腾讯云联合中国信通院&作业帮等首发《降本之源-云原生成本管理白皮书》
  3. Qemu/kvm虚拟化源码解析学习视频资料
  4. Swift-技巧(十一)重写运算符
  5. 日常Java 2021/10/31
  6. SpringMVC注解详情
  7. Mysql 常见报错和疑问汇总
  8. Mysql百万级数据索引重新排序
  9. 【力扣】两个数组的交集 II
  10. 6、Redis五大数据类型---列表(List)