Golang slice 的使用方法及注意事项

一、说明

切片 (slice) 是 golang 里面的可变长元素类型,不是数组或数组指针,本质是一个结构体

slice 的声明如下 (位于安装目录下的 src/runtime/slice.go):

值得注意的是,切片除了有一个 len 属性表明当前切片长度以外,还有一个容量标识 cap,表示切片的最大容量,len 小于等于 cap 。查看长度和容量的方法很简单,直接使用 len()cap()即可。

二、创建方式

1. 直接创建

也可以使用索引号指定

2. 基于数组创建

通过给定数组的下标范围来创建切片,创建的时候,切片长度等于我们实际赋值的长度,容量默认等于数组第一个被赋值的元素最后一个元素的距离:

这个距离也可以显式指定:

s_data := data[x:y:z]的含义如下:

  • x 表示赋值的起始索引,从 x 开始赋值。
  • y 表示赋值的结束索引,长度就是 x-y 的距离。
  • z 表示容量最大可以到的索引,x-z 的距离是容量。

通过数组创建的切片和数组共享同一块内存区域,修改切片的时候数组也会随之改变:

3. 使用 make 创建

语法形式是 make([]Type, Len, Cap),Type 是想要创建的切片类型,Len 是切片长度,Cap 是切片容量。

cap 不是必需的,可以省略不写,默认等于 len:

三、使用示例

输出:

四、和数组定义的区别

1. 数组的定义:

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

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

2. 切片的定义:

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

s := make([]s, 3)

五、注意事项

切片本质是一个结构体,使用时拷贝传递。在使用切片做函数形参时,会创建一个临时变量,但内部的数据还是不变。

输出:

可以看到 s 的地址变了,但是内部 s[0], s[1]的地址还是一样的,说明在创建副本的时候只是简单拷贝了切片的值,并没有把内部的内存空间重新分配。所以当我们使用 range 或者把切片作为函数形参时在代码块内部直接就会修改切片的值。

但是在要注意的是在把切片作为函数形参时,在函数内部使用 append 就不会对切片产生影响:

原理很简单,因为 append 会返回一个新的 slice 给 a,而 as 的一个副本,所以这里对 s 就不会有任何影响,此时要想修改 s 可以把切片改成指针类型:

 

发表评论