3

由于切片的底层是数组 所以先从数组说起

数组

零值数组声明

var arr [5]int

字面量数组声明

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

三个点自动计算数组长度

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


切片

需要说明一下,切片本质是对数组的抽象和封装,其包含3个字段

  • 指向底层数组的指针
  • 长度(切片中实际元素的个数)
  • 容量(切片中允许存放的元素个数)
    切片的底层实现

声明长度和容量相等的切片

slice := make([]string, 6)

声明长度和容量不等的切片

slice := make([]string, 3,6)

字面量声明切片

slice := []int {1, 2, 3)

索引声明切片

slice := []string{99,""}

nil切片

var slice []int

空切片

slice := make([]int, 0)
或者
slice := []int{}

切片元素的赋值

s := []int {1,2,3,4,5}
//修改索引为2的值为8
s[2]= 8

切片上创建切片

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

为切片追加元素

s := []int {1,2,3,4,5}
s = append(s, 9)

这里需要说明一下的是,append返回的结果其实是一个新的切片,如果追加元素后,底层数组不需要扩容,那么切片和底层数组长这样:

如果追加元素后,底层数组需要扩容(本质就是将原数组的数据复制到一个容量更大的数组中然后再追加新的值),那么切片和底层数组长这样:

切片的第三个索引

用三个参数声明的切片 长度和容量要做一下运算,稍微复杂一丢丢

对了 这里书里推荐了一个最佳实践:在append的时候尽量创建长度和容量等长的切片,也就是尽量不要用第三个参数,为什么呢?

  • 根据前面的切片底层实现 我们知道 切片是对底层数组的封装,同时可能有多个切片指向同一个底层数组,如果len != cap 有可能导致切片1修改了底层数组影响到了切片2,但如果len==cap 那么append的时候必然会创建一个新的数组,切片2会指向这个新的底层数组
  • 每次扩容数组的长度都是原长度的2倍

参考:Kennedy W , Ketelsen B , Martin E S . Go in action. 2016.


LiberHome
409 声望1.1k 粉丝

有问题 欢迎发邮件 📩 liberhome@163.com