[golang] slice切片扩容规则解析

前言

golang的slice切片大家应该都用过,如果说他就是个数组,那是不准确的。在这里我会和大家一起探讨golang中切片的一些逻辑。

slice组成

如图:
slice组成

其中:
data包含真实的地址和字节长度,你可以理解为就是我们传统意义上理解的数组连续内存;
len表示实际的切片内元素数量;
cap表示切片的真实底层数量;
cap不能小于len。

  • :什么情况下cap大于len呢,什么情况下又等于?
    通过几个初始化代码来解析:
// 生成一个容量是10的切片数组,这里cap==len==10
make([]int,10)
// 生成一个容量是10的切片数组,但是cap==20 len==10 cap>len
make([]int,10,20)

其实这个cap是程序预先为我们的这个切片对象申请的空间;
而len是我们这个切片实际能使用的空间;

cap存在的意义

首先我们要明确一点,数组一定是在内存中是连续的一段内存块。
对于我们golang中的slice,其实是有封装一个元素递增的功能也就是Append;
Append方法可以使我们很方便的将新元素放到我们的slice里。

  • 但是使用他之余,我们不禁会想,slice中的data实际上也是个数组啊,数组怎么能像链表一样随意递增呢?
    其实所谓append的核心原理也是相当于为slice中的data重新申请一块比之前更大的连续的内存段,然后将原data的数据迁移到新申请的内存段中。
    在这里插入图片描述
    这个应该是我们在写c、c++的时候数组扩容常用的方式,也是golang数组扩容用到的,但是除此外slice切片就没什么特点了么?;

  • cap闪亮登场
    我们举个例子:

/* 通过上文讲解,可以理解这样做相当于为我们的slice中的data预申请
了100空间大小的内存,只不过当前可用的大小是10*/
arr:=make([]int,10,100)

那么如果我们已经往arr切片中塞入了10个元素后,当我们继续往arr切片塞数据的时候,此时并不会触发重新申请更大内存空间的动作,因为毕竟预先申请了100的连续内存空间,就继续在原来的内存段上扩容即可。

  • 好处
    通过预先申请空间这样子的逻辑操作,避免了因为频繁新增数据,导致程序对内存的频繁访问,以及数据频繁的迁移。节省开支;

slice扩容规则

上文讲解了slice的cap存在的意义,预先申请一大段内存段上,规避了因为频繁的增加数组元素导致的程序对内存的频繁操作。但是cap毕竟也有用完的时候,当cap等于len的时候(实际元素数量等于slice预先申请的空间数量)就会触发slice扩容;
slice扩容简言之和上文的数组扩容一致,就是找个更大的内存段拿来用,然后将原data数据迁移

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值