Go中的切片Slice

她們都叫我劍俠發表於2019-02-28

Go中的切片Slice

切片概念

切片是一種資料結構, 是一種動態陣列, 按需自動改變大小, 可以方便的管理和使用資料集合

內部實現

  1. 切片基於陣列實現的, 切片的底層是陣列。
  2. 切片本身非常小, 是對陣列的抽象
  3. 因為切片基於陣列實現的, 所以底層的記憶體是連續分配的, 效率非常高
  4. 切片可以通過索引獲得資料, 可以迭代以及垃圾回收優化
  5. 切片是對陣列view的對映, 公用底層陣列, 改變切片就會改變底層陣列

切片宣告和初始化

宣告

  • make方法, 單獨引數, 既指定長度也指定容量

  • // 長度和容量都是5
        slice := make([]int, 5)
    複製程式碼
  • make方法, 兩個引數, 指定長度和容量

  • // 長度為5, 容量為10(容量對應底層陣列)
    slice := make([]int, 5, 10)
    
    複製程式碼
    1. 切片的底層為陣列, 切片不指定值預設為零值
    2. 切片長度為5, 容量為10, 所以只能訪問5個值
    3. 剩下5個元素需要切片擴充後才能訪問
    4. 切片的容量必須 >= 切片的長度
  • 使用:=建立切片

    // 此時切片的長度和容量都是5
      slice:=[]int{1,2,3,4,5}
    複製程式碼
  • 使用:=建立部分切片

    // 此時切片的長度和容量都是5
    slice:=[]int{4:1}
    複製程式碼
  • 陣列和切片的區別

    //陣列
    array:=[5]int{4:1}
    //切片
    slice:=[]int{4:1}
    複製程式碼
  • nil切片和空切片的區別,
    他們的長度和容量都是0, 指向的底層陣列不同

    • nil切片指向底層陣列的指標為nil, 表示不存在的切片
    • 空切片指向的底層陣列為指標為地址, 表示空切片集合
    //nil切片
    var nilSlice []int
    //空切片
    slice:=[]int{}
    複製程式碼

基於現有的陣列或者切片建立切片

  1. 使用[i:j]來建立新的切片, i為索引開始, j為索引結束, 半開半閉區間, 包含i, 不包含j
  2. i 和 j 都可省略, 省略後預設為 0 和 len(slice) – 1
  3. 對於陣列或者切片(容量為k)建立新的切片(slice[i:j])後的長度和容量為
    長度為j - i, 容量為k - i
  4. 系統內建方法長度為len(slice), 容量為cap(slice)

使用第三個值來限制切片容量

  1. 建立了一個長度為 2 - 1 = 1, 容量為3 - 1 = 2
  2. 第三個值不能超過原切片容量的最大值
slice := []int{1, 2, 3, 4, 5}
newSlice := slice[1:2:3]
複製程式碼

向切片追加值

  1. 通過append方法向切片追加值
slice := []int{1, 2, 3, 4, 5}
newSlice := slice[1:3]

newSlice=append(newSlice,10)
fmt.Println(newSlice)
fmt.Println(slice)
//Output
[2 3 10]
[1 2 3 10 5]
複製程式碼
  1. 通過append同時追加許多值
newSlice=append(newSlice,10,20,30)
複製程式碼
  1. 通過...append向切片中追加切片
slice := []int{1, 2, 3, 4, 5}
newSlice := slice[1:2:3]

newSlice = append(newSlice, slice...)
複製程式碼
  1. append函式會智慧的增長底層陣列的容量,目前的演算法是:容量小於1000個時,總是成倍的增長,一旦容量超過1000個,增長因子設為1.25,也就是說每次會增加25%的容量。

迭代切片

  1. 使用for range迭代切片
slice := []int{1, 2, 3, 4, 5}
for i,v:=range slice{
	fmt.Printf("索引:%d,值:%d
",i,v)
}
複製程式碼
  1. 也可以使用for迭代切片
slice := []int{1, 2, 3, 4, 5}
for i := 0; i < len(slice); i++ {
	fmt.Printf("值:%d
", slice[i])
}
複製程式碼

注意點

  1. range返回的是切片元素的複製, 不是元素的引用

在函式中傳遞切片

func main() {
	slice := []int{1, 2, 3, 4, 5}
	fmt.Printf("%p
", &slice)
	modify(slice)
	fmt.Println(slice)
}
func modify(slice []int) {
	fmt.Printf("%p
", &slice)
	slice[1] = 10
}
複製程式碼

注意點

  1. 傳遞複製切片時, 底層陣列不會被複制, 也不會收影響, 複製只是複製的切片本身, 不涉及底層陣列

相關文章