詳解 go 的切片

pureyb發表於2019-08-06

語義理解切片

go語言中的切片是go語言的一個特色,從語義上來說,切片就是把一個整體的東西切分成小的部分,那麼對於語言中的切片也是同理。
舉個例子看如下程式碼:

package main
import "fmt"
func main() {
    arr := [...]int{0, 1, 2, 3, 4, 5, 6, 7}
    fmt.Println("arr[2:6]:", arr[2:6])  // 從下標2到下標6
    fmt.Println("arr[:6]:", arr[:6])    // 從下標0到下標6
    fmt.Println("arr[2:]:", arr[2:])    // 從下標2到最後
    fmt.Println("arr[:]:", arr[:])  // 全部
}

輸出結果為:

arr[2:6]: [2 3 4 5]
arr[:6]: [0 1 2 3 4 5]
arr[2:]: [2 3 4 5 6 7]
arr[:]: [0 1 2 3 4 5 6 7]

這裡可以很明確的看出,我們想要arr 陣列的哪一部分,我們就切哪一部分。

當然,如果僅僅知道切片是這麼用的當然還不夠,我們應該更加深入的理解,如:

對原陣列的 copy 還是 view

對於go語言的陣列,copy 和 view 是同時都存在的。

  • copy 就是使用這個陣列的時候我將這個陣列拷貝一份,這樣對於陣列的增刪改,是不會改變原陣列的值的
  • view 由陣列執行切片所返回的物件是一個view,即檢視,若我們在檢視上運算元組,會改變原陣列,

copy場景

package  main

import  (
  "fmt"
)

func  updateArr(arr [5]int)  {
  arr[0]  =  100
  fmt.Println("修改後的arr:", arr)
}

func  main()  {
  arr3  :=  [...]int{2,  4,  5,  6,  7}
  fmt.Println("原來的:", arr3)
  updateArr(arr3)
  fmt.Println("再次檢視原始的:", arr3)
}
輸出結果:
原來的: [2 4 5 6 7]
修改後的arr: [100 4 5 6 7]
再次檢視原始的: [2 4 5 6 7]

如上程式碼可以看到,我們在updateArr 裡面修改了下標為0的值,但是我們輸出原始陣列的時候,並沒有變。這就是對陣列copy。

view場景

func  updateArr(arr []int)  {
  arr[0]  =  100
  fmt.Println("修改後的arr:", arr)
}

func  main()  {
  arr3  :=  [...]int{2,  4,  5,  6,  7}
  fmt.Println("原來的:", arr3)
  // 使用切片
  updateArr(arr3[:])
  fmt.Println("再次檢視原始的:", arr3)
}
輸出結果:
原來的: [2 4 5 6 7]
修改後的arr: [100 4 5 6 7]
再次檢視原始的: [100 4 5 6 7]

為什麼view能夠改變原陣列

雖然Slice本身是值型別,但是它內部使用了對陣列的指標引用,所以修改切片資料,會將陣列原有資料修改掉。

當然,在理解上面的同時,一定要知道go是如何定義一個切片的

var b []int

所以,在 updateArr 這個函式傳參的時候 arr []int 是傳切片進去。不然會報錯。

相關文章