golang 定义一个空切片_Golang切片的实现

本文详细介绍了Golang中切片的概念,包括切片与数组的关系、切片的数据结构、创建切片的方式,尤其是空切片与nil切片的区别。此外,文章还探讨了切片的扩容策略,强调了避免不必要的内存拷贝以优化性能的重要性。最后,提到了使用`for range`迭代切片时应注意的值拷贝问题。
摘要由CSDN通过智能技术生成

前言:切片的设计思想来源于动态数组,是为了开发者能更加方便地使用使一个数据结构能自动增加和减少,但是切片本身并不是动态数组。

1、切片与数组

Go是值传递的,用切片传递数组参数,既可以达到节约内存的目的,也可以达到合理处理好共享内存的问题。但是也有反例,并非所有时候都适合用切片代替数组,因为切片底层数组可能会在堆上分配内存,而且小数组在栈上拷贝的消耗未必比make消耗大。

2、切片的数据结构

切片本身并不是动态数组或者数组指针。它内部实现的数据结构通过指针引用底层数组,设定相关属性将数据读写限定在制定的区域内。切片本身是一个只读对象,其工作机制类似数组指针的一种封装。type slice struct {

array unsafe.Pointer

len int

cap int

}

3、创建切片

创建切片有两种形式,make 创建切片,空切片。

3.1、make 和切片字面量

make创建切片

字面量创建切片

3.2、nil和空切片var slice []int

nil切片

空切片一般会用来表示一个空的集合。比如数据库查询,一条结果也没有查到,那么就可以返回一个空切片。silce:=make([]int,0)

slice:=[]int{}

空切片

空切片和 nil 切片的区别在于,空切片指向的地址不是nil,指向的是一个内存地址,但是它没有分配任何内存空间,即底层元素包含0个元素。

4、切片扩容

Go 中切片扩容的策略是这样的:

1)首先判断,如果新申请容量(cap)大于2倍的旧容量(old.cap),最终容量(newcap)就是新申请的容量(cap)

2)否则判断,如果旧切片的长度小于1024,则最终容量(newcap)就是旧容量(old.cap)的两倍,即(newcap=doublecap)

3)否则判断,如果旧切片长度大于等于1024,则最终容量(newcap)从旧容量(old.cap)开始循环增加原来的 1/4,即(newcap=old.cap,for {newcap += newcap/4})直到最终容量(newcap)大于等于新申请的容量(cap),即(newcap >= cap)

4)如果最终容量(cap)计算值溢出,则最终容量(cap)就是新申请容量(cap)

注意:扩容扩大的容量都是针对原来的容量而言的,而不是针对原来数组的长度而言的。

新数组 or 老数组 ?

扩容后使用老数组

由于原数组还有容量可以扩容,所以执行 append() 操作以后,会在原数组上直接操作,所以这种情况下,扩容以后的数组还是指向原来的数组。这种情况也极容易出现在字面量创建切片时候,第三个参数 cap 传值的时候,如果用字面量创建切片,cap 并不等于指向数组的总容量,那么这种情况就会发生。

情况二:

情况二其实就是在扩容策略里面举的例子,在那个例子中之所以生成了新的切片,是因为原来数组的容量已经达到了最大值,再想扩容, Go 默认会先开一片内存区域,把原来的值拷贝过来,然后再执行 append() 操作。这种情况丝毫不影响原数组。

所以建议尽量避免情况一,尽量使用情况二,避免 bug 产生。

4、切片迭代 for range

for range

由于 Value 是值拷贝的,并非引用传递,所以直接改 Value 是达不到更改原切片值的目的的,需要通过 &slice[index] 获取真实的地址。

有疑问加站长微信联系(非本文作者)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值