Golang----切片

一、切片与数组的区别

(1)切片是一个长度可变的数据类型,其长度在定义时可以为空,也可以指定一个初始长度。数组是一个长度固定的数据类型,其长度在定义时就已经确定了,不能动态改变。

(2)切片的内存空间是在运行时动态分配的,其大小可以改变;数组的内存空间是在定义时分配的,其大小是固定的。

(3)切片作为函数的参数时,传递的是底层数组。函数操作切片的引用,会影响底层数组;数组作为函数参数时,函数操作的是数组的一个副本,不会影响原始数组。

(4)切片有容量的概念,指的是分配的内存空间。且切片本身是一个结构体。

二.切片自身结构体及与底层数组

在Golang里,切片本身是一个结构体,包含三个字段。

type slice struct{
    array unsafe.Pointer //指向第一个元素的地址
    len int
    cap int
}

1.指针: 指向 slice 可以访问到的第一个元素。
2.长度: slice 中元素个数。
3.容量: slice 起始元素到底层数组最后一个元素间的元素个数。

当切片是截取已定义数组而定义时,切片是数组的一个引用,修改切片的值会直接修改数组的值。当直接通过make定义切片或直接声明切片或基于另一个切片定义时,切片的底层数组对程序员是不可见的,只能通过切片操作底层数组。(当切片基于另一个切片定义时,两者共享同一个底层数组)

三、切片的扩容机制

Go 中切片的扩容机制是基于动态数组的,这意味着切片的底层数组会动态调整大小以适应元素的增加。下面是 Go 切片扩容的一般过程:

1.初始分配:

当使用 make 创建一个切片时,Go 会为其分配一块初始的底层数组

2.追加元素:

使用 append 向切片追加元素时,Go 会检查是否有足够的容量来容纳新的元素。如果有足够的容量,新元素会被添加到底层数组的末尾,切片的长度会增加。如果没有足够的容量,就需要进行扩容。

3.扩容:

当切片需要扩容时,Go 会创建一个新的更大的底层数组(具体的扩容策略看下面扩容原理)。然后,原数组的元素会被复制到新数组中,新元素会被添加到新数组的末尾。最后,切片的引用会指向新的底层数组,原数组会被垃圾回收。

扩容过程                                                                                                                                          1.如果期望容量大于当前容量的两倍就会使用期望容量;
2.如果当前切片的长度小于阈值(默认 256)就会将容量翻倍;
3.如果当前切片的长度大于等于阈值(默认 256),就会每次增加 25% 的容量,基准是 newcap + 3*threshold,直到新容量大于期望容量;

总的来说,Go的设计者不断优化切片扩容的机制,其目的只有一个:就是控制让小的切片容量增长速度快一点,减少内存分配次数,而让大切片容量增长率小一点,更好地节省内存。

如果只选择翻倍的扩容策略,那么对于较大的切片来说,现有的方法可以更好的节省内存。
如果只选择每次系数为1.25的扩容策略,那么对于较小的切片来说扩容会很低效。
之所以选择一个小于2的系数,在扩容时被释放的内存块会在下一次扩容时更容易被重新利用

  • 25
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值