因为数组的长度是固定、传值机制会导致较大的内存拷贝开销,因此在 Go 语言中很少直接使用数组。
切片是一个拥有相同类型元素的可变长度的序列,它是基于数组类型做的一层封装,功能更灵活,支持自动扩容和收缩。

每个切片包含三个字段:

  • array: 是指向底层数组的指针;
  • len:是切片的长度,即切片中当前元素的个数;
  • cap:是底层数组的长度,也是切片的最大容量,cap值永远大于等于len值。

Go编译器会自动为每个新创建的切片建立一个底层数组,默认底层数组的长度与切片初始元素个数相同。

创建切片

  1. s := make([]string, 6, 10) // 10位cap的值,即底层数组长度,6为切片的初始长度
  2. // 如果没有再make中指定cap参数,那么底层数组长度cap就等于len
  3. s := make([]string, 6) // cap = len = 6
  4. s := []string{}
  5. s := []string{"a", "b", "c"}
  6. s := []string{1: "a", 2: "b", 3: "c"}

添加元素

  1. s := make([]string, 6, 10)
  2. s = append(s, "a", "b")
  3. fmt.Printf("%#v\n", s) // []string{"", "", "", "", "", "", "a", "b"}

获取切片长度和容量

  1. fmt.Println(len(s), cap(s))

遍历切片

  1. // for
  2. for i := 0; i < len(s); i++ {
  3. fmt.Println(i, s[i])
  4. }
  5. // range
  6. for i, v := range s {
  7. fmt.Println(i, v)
  8. }

切片删除

Go没有直接的切片删除功能

  1. package main
  2. import "fmt"
  3. func main() {
  4. s := []int{1, 2, 3, 4, 5}
  5. // 移除第一个元素
  6. s = s[1:]
  7. // 移除最后一个元素
  8. s = s[:len(s)-1]
  9. fmt.Println(s) // [2 3 4]
  10. }

切片的动态扩容

“动态扩容”指的就是,当我们通过append操作向切片追加数据的时候,如果这时切片的len值和cap值是相等的,也就是说切片底层数组已经没有空闲空间再来存储追加的值了,Go运行时就会对这个切片做扩容操作,来保证切片始终能存储下追加的新值。

当切片的len值和cap值相等的情况下继续向切片追加数据时,append会判断出底层数组剩余空间不够,就会创建一个新的底层数组,这个新的底层数组的长度等于之前底层数组长度的2倍,也就是切片的容量,新的底层数组建立后,append会把旧底层数组中的数据拷贝到新数组中,之后新数组便成为了切片的底层数组,旧的底层数组会被垃圾回收掉。