由於切片的底層是陣列 所以先從陣列說起
陣列
零值陣列宣告
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.