Golang-slice理解

slice



注:以下内容是看小徐的公众号及B站学习源码做的笔记,个人理解,仅供参考

go为何设计slice?

切片对标其他语言的动态数组,底层通过数组实现,可以说是对数组的抽象,底层的内存是连续分配的所以效率高,可以通过索引查找。
image.png
**有数组了为何还要切片? **

  1. 数组长度固定,切片动态扩容,更加灵活
  2. golang官方文档明确说了go只有值传递,而通过切片可通过值传递实现引用传递

所以切片的核心在于它如何实现引用传递、 以及 切片的扩容机制

引用传递实现

切片实现引用传递主要还是跟它的数据结构有关。 在slice的结构体中有3个字段, array, len, cap; 其中的array指向底层数组开始的内存。 那么值传递的时候传的内存区域其实是同一块。此时虽然对副本修改,但实际上改的是同一块内存上的数据,就实现了引用传递。 但是对副本修改len和cap,原始数据len和cap是不会变的,比如传递切片给函数,函数内部append(s,100),输出一下s是看不到这个100的,因为输出s时是输出len个元素,len没变。

扩容机制

1.19下slice.go下的grouslice方法源码

扩容的触发时机:len跟cap相等时,下次append就是触发扩容。阅读slice.go下的growslice方法源码,可以分析slice扩容机制。
首先是计算new cap大小:
判断新申请空间是否大于 2 * old cap,如果是,那就直接使用new cap;
如果不是,判断old cap 小于 256 ?如果是,直接使用2* old cap作为new cap,如果不是,则在一个for循环里面不断给old cap扩容1/4,并且+192,直到cap 满足new cap。 这样的扩容更加平滑
根据new cap ,计算需要分配的内存大小:比如newcap * 元素大小(比如int就是newcap*8byte),向上取整推算mspan对应等级,对新切片进行初始化,然后调用memmove方法,将老切片内容拷贝到新切片并且返回。

我觉得go的切片扩容策略相比C++更加的平滑,初始阶段的扩容迅速,后面的增加更省内存。像C++的vector的话linux下1.5倍考虑到内存的复用,win+vs下2倍,是固定的倍数扩容;

  • 4
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值