Go基础之切片

定义以及初始化

切片是一个拥有相同类型元素的可变长度的序列。它是基于数组类型做的一层封装,支持自动扩容。

切片是一个引用类型,它的内部结构包含地址、长度和容量。

切片: 指针、长度、容量

声明语法:

var name []T

例如:

1
2
3
4
5
6
7
8
var s1 []int
// []
fmt.Println(s1)
// true 没有分配内存 == nil 故打印输出true
fmt.Println(s1 == nil)
s1 = []int{1, 2, 3}
// [1 2 3]
fmt.Println(s1)

切片的长度和容量

可以通过使用内置的len()函数求长度,使用内置的cap()函数求切片的容量

切片表达式

切片的底层就是一个数组,所以可以基于数组通过切片表达式得到切片。切片表达式中的 lowhigh 表示一个索引范围(左包含,右不包含)

1
2
3
4
5
6
// 数组
array := [5]int{1, 2, 3, 4, 5}
// 切片
slice := array[1:3]
// slice:[2 3] len(slice):2 cap(slice):4
fmt.Printf("slice:%v len(slice):%v cap(slice):%v\n", slice, len(slice), cap(slice))

当然也可以忽略表达式中的索引。省略了low 则默认是 0,省略了high 则默认为切片操作数的长度

1
2
3
4
array := [5]int{1, 2, 3, 4, 5}
slice1 := array[1:]
slice2 := array[:3]
slice3 := array[:]

对切片在进行切片,high 的上限边界是切片的容量 cap(slice),而不是长度

1
2
3
4
5
6
7
array := [5]int{1, 2, 3, 4, 5}
slice := array[1:5]
// slice:[2 3 4 5] len(slice):4 cap(slice):4
fmt.Printf("slice:%v len(slice):%v cap(slice):%v\n", slice, len(slice), cap(slice))
subSlice := slice[3:4] //这里的索引上限是slice的容量4
// subSlice:[5] len(subSlice):1 cap(subSlice):1
fmt.Printf("subSlice:%v len(subSlice):%v cap(subSlice):%v\n", subSlice, len(subSlice), cap(subSlice))

使用 make() 函数构造切片

格式:

make([]T, size, cap)

其中

  • T: 切片元素类型
  • size: 切片中元素的数量
  • cap: 切片的容量
1
2
3
4
// 声明并初始化一个切片 make初始化 分配内存
s10 := make([]int, 2, 10)
// s10:[0 0] len(s10):2 cap(s10):10
fmt.Printf("s10:%v len(s10):%v cap(s10):%v\n", s10, len(s10),cap(s10))

切片是引用类型

切片不存值, 下方的示例代码s1s2底层指向同个数组, 故修改s2也影响了s1

1
2
3
4
5
6
s1 := []int{1, 2, 3} // [1 2 3]
s2 := s1
fmt.Println(s2) // [1 2 3]
s2[1] = 200
fmt.Println(s1) // [1 200 3]
fmt.Println(s2) // [1 200 3]

切片的扩容策略

  1. 如果申请的容量大于原来的 2 倍,那么就直接扩容至新申请的容量
  2. 如果小于 1024,那么直接两倍
  3. 如果大于 1024,就按照 1.25 倍去扩容
  4. 具体存储的值的类型不同,扩容策略也有一定的不同

append 为切片添加元素

1
2
3
4
5
6
7
var s1 []int
// s1 = make([]int, 1)
// 直接赋值会报错,因为没有初始化内存, 需要上一行的make进行初始化
// s1[0] = 100
// 自动初始化切片
s1 = append(s1, 1)
fmt.Println(s1)

append 还会自动扩容

copy 复制切片

1
2
3
4
5
6
s1 := []int{1, 2, 3}
// var s2 []int // 声明了但是未初始化分配内存, copy失败,打印为空
// var s2 = make([]int, 0, 3) // 虽然make初始化了但是长度是0, copy不会自动扩容
var s2 = make([]int, 3, 3) // 这个是可以copy成功的
copy(s2, s1)
fmt.Println(s2)

切片的遍历

和数组一致,支持 forfor range

1
2
3
4
5
6
7
8
9
s := []int{1, 3, 8, 11}

for i := 0; i < len(s); i++ {
fmt.Println(i, s[i])
}

for index, value := range s {
fmt.Println(index, value)
}

学习资料

  1. https://www.bilibili.com/video/BV1fz4y1m7Pm/?p=22
  2. https://www.liwenzhou.com/posts/Go/06_slice/

我的环境

  • Mac
  • go1.19
  • GoLand