Golang Slice

Golang—Slice

Slice是Go语言中的一种数据类型,又称动态数组,依托数组实现,可以方便的进行扩容、传递等,实际使用中比数组更灵活。

实现原理

Slice依托数组实现,底层数组对用户屏蔽,在底层数组容量不足时可以实现自动重分配并生成新的Slice。

img

扩容

slice的扩容可以分为以下两种情况:

  1. 原slice的容量够用
    这种情况下,扩容以后的指针还是指向原来的数组,对一个slice的操作可能影响多个指针指向相同地址的 Slice。
    img
  2. 原slice的容量不够用
    如果原来数组的容量已经达到了最大值,再想扩容, Go 默认会先开一片内存区 域,把原来的值拷贝过来,然后再执行 append() 操作。也就是说这是2块不同的内存地址,相互不影响。
    (这里我只是做个示范,并不代表就一定会扩容2个cap,具体的扩容还需要按照扩容规则来)
    img

具体扩容规则

规则1

  • 需要的容量大于原切片容量的两倍时,会使用需要的容量作为新容量;
  • 当原切片长度小于1024时,新切片的容量会直接翻倍;
  • 而当原切片的容量大于等于1024时,会反复地增加25%,也就是变为原来容量的1.25倍,直到新容量超过所需要的容量。

规则2

  • 如果扩容之后还没有超过原数组的容量,那切片中的指针指向的位置还是原数组;
  • 如果扩容之后超过了原数组的容量,那就会开辟一块新的内存,把原来的值拷贝过来,这种情况丝毫不会影响到原数组。

使用append()向Slice添加一个元素的实现步骤如下:

  1. 假如Slice容量够用,则将新元素追加进去,Slice.len++,返回原Slice
  2. 原Slice容量不够,则将Slice先扩容,扩容后得到新Slice
  3. 将新元素追加进新Slice,Slice.len++,返回新的Slice。

总而言之,扩容只关心的slice的cap,长度是跟着append进行变化的。

深浅copy

  1. 深拷贝:拷贝的是数据本身,创造一个新对象,新创建的对象与原对象不共享内存,新创建的对象在内存中开辟一个新的内存地址,新对象值修改时不会影响原对象值

实现深拷贝的方式:

  • copy(slice2, slice1)
    • 并且使用copy()内置函数拷贝两个切片时,会将源切片的数据逐个拷贝到目的切片指向的数组中,拷贝数量取两个切片长度的最小值,多余的则会丢失。也就是说copy过程中不会发生扩容。
    • 例如下图(slice2中的9,10则会丢失)
      img
  • 遍历append赋值
  1. 浅拷贝:拷贝的是数据地址,只复制指向的对象的指针,此时新对象和老对象指向的内存地址是一样的,新对象值修改时老对象也会变化

实现浅拷贝的方式:

引用类型的变量,默认赋值操作就是浅拷贝

slice2 := slice1

Slice总结

  1. 每个Slice底层都是由一个array来进行维护。
  2. slice的扩容需要根据实际情况进行实际判断。
  3. 使用append()向切片追加元素时有可能触发扩容,扩容后将会生成新的切片
posted @   Asakalan  阅读(44)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
点击右上角即可分享
微信分享提示