golang中slice结构定义

切片是一个拥有相同元素的可变长序列,且slice的定义与数组的定义非常像,它就是没有长度的数组

对于slice的结构体,reflect.sliceheader的定义如下

type SliceHeader struct {

Data  uintptr

Len int

Cap int

}

可以看到slice有三个属性:指针,长度和容量,指针指向slice开始访问的第一个元素,长度是切片的长度;

cap是指slice开始访问的第一个元素到底层数组最后一个元素的元素个数,slice的长度不可以超过slice的容量

切片是底层的数组,go语言的切片对应着底层数组,一个底层数组可以对应多个slice

基本操作

  首先来了解一下slice的定义

s :=[]int{1,2,3,4,5}

如果只是想创建一个slice而不赋值,那么可以使用make函数进行操作

ss  := make ([]int,10)

上面的实例通过make函数定义了一个[]int类型的切片,长度为10,定义时可以设定第三个参数cap。默认cap与len一致,对于数组元素,由于没有设定具体的初始值,因此元素都会取对应的元素类型int的初始默认值0

 forr遍历slice 

for i,v := range ss  {

fmt.Println(i,v)

}

运行后输出的值都是0,而下边是从0到9,证明make分配了一块内存空间,如果想主动释放slice的空间,可以通过为他赋值nil实现

ss  = nil

 第10行至第11行对切片的元素重新赋值,然后分别打印数组a和切片ss,切片的操作不仅影响了切片本身,也影响了数组。可知ss切片其实是指向数组a的引用。

可以看到切片的data是指向起始元素的指针,而长度根据赋值时的开始和结束下边进行推理。cap是从起始元素到数组最后一个元素的元素个数可以通过cap函数取得。结束的部分是数组最后一个元素。

 不管是数组还是切片都可以一s[i:j] 0 <=i=j<=cap(s)的方式进行操作,注意每次取元素都是左闭右开,而且i和j都是默认值,如果不写i默认是0,j默认是caps

数组作为函数形参要注意使用指针,而slice就不存在这个问题,slice传递的本就是地址,也就是reflect.sliceHeader,不会复制值,对切片的操作也会直接影响原来的数组和切片

append

slice的长度是动态的,那么若要给slice增加元素应该如何操作呢

通过append可以在原来的切片上插入元素,可以在开头,结尾,指定位置插入元素或者其他slice

使用初始值的方式定义了一个slice,打印了一下切片a的cap,cap=len 

 

append为切片a在尾部追加了一个元素333,cap变成了6,这是slice的自动扩容,如果发现当前的容量不足以容纳新元素,则自动扩展为原来的2倍,当长度太长时,是1.5倍

向切面a追加一个新的切片,新的切片包含三个元素。打印机cap ,发现容量变成了12

cpoy 

 切片之间的元素赋值可以利用copy

先定义了两个切片,然后使用copy将b1复制到a1,因为a1比b1长,所以前三个元素变为-1,后两个元素保持不变。cpoy(x,y) y复制给x

a2复制给b2,因为a2比b2长,所以b2的三个元素都变成2

copy的参数必须是slice,不能是数组,所以如果数组a要使用copy 则需要传递a[:]

其他

切片和数组一样都是可以多维的,本书只介绍go语言里面的重点,多维部分就略过了

数组可以为空,也就是有0个元素,切片也可以为空,长度可以为0,但容量不为0,也可以两者都为0。此处需要注意,长度和容量都为0的切片并不等于nil,不能用是否等于nil进行判断,而是要根据长度和容量进行判断。

因为slice是通过指向的底层数组来存储数据的,而且可能有多个slice指向同一个底层数组,这样就会导致一个情况,如果一个小的切片指向这个底层数组,将会导致底层数组处于使用状态而无法被垃圾回收。

也有一种比较极端的情况,可能我们只使用了底层数组的一个元素,而导致底层数组的所有元素不能被回收。在这种情况下,虽然会报错,但是会占用太多内存,可能导致运行速度变慢。

a := []int {1,2,3,4,5}

a = append(a[:0],a[:3]...)

若删除了后面的两个元素,切片的容量不会变,垃圾回收机制也不会回收后面已删除的两个元素。若想让切片的容量相对减少,有一种方法就是在删除之前,先把a[3]赋值为nil

建议仅在切片声明周期长,底层数组较大的情况下使用这种处理方式,因为这种方式本身也是有系统开销的,在声明周期比较短或者底层数组不长的情况下,不应考虑这种方式。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值