go 中的slice與數組
數組
go中的數組與C語言中的數組類似,但是不同的是C中的數組名其實還是指針,在作為參數傳遞的過程中會退化為指針,而go語言則是在編譯期間就確定其大小,然后始終是作為值傳遞的。
初始化
[5] int {1,2,3,4,5}
長度為5的數組,其元素值依次為:1,2,3,4,5[5] int {1,2}
長度為5的數組,其元素值依次為:1,2,0,0,0 。在初始化時沒有指定初值的元素將會賦值為其元素類型int的默認值0,string的默認值是""[...] int {1,2,3,4,5}
長度為5的數組,其長度是根據初始化時指定的元素個數決定的[5] int { 2:1,3:2,4:3}
長度為5的數組,key:value,其元素值依次為:0,0,1,2,3。在初始化時指定了2,3,4索引中對應的值:1,2,3[...] int {2:1,4:3}
長度為5的數組,起元素值依次為:0,0,1,0,3。由於指定了最大索引4對應的值3,根據初始化的元素個數確定其長度為5
作為參數傳遞
例如:
package main
import (
"fmt"
"reflect"
)
func modifySlice(array []int) {
array[0] = 10
}
func modifyArr(array [5]int) {
array[0] = 10
}
func modifyPt(array *[5]int){ // 作為指針傳遞
(*array)[0] = 10
}
func main(){
arr := [...]int{1,2,3,4,5}
fmt.Println(reflect.TypeOf(arr))
modifyArr(arr)
fmt.Println("In main(), arr values:", arr)
modifyPt(&arr)
fmt.Println("In main(), arr values:", arr)
sli := []int{1,2,3,4,5}
fmt.Println(reflect.TypeOf(sli))
modifySlice(sli)
fmt.Println("In main(), sli values:", sli)
}
// 輸出結果為
//[5]int
//In main(), arr values: [1 2 3 4 5]
//In main(), arr values: [10 2 3 4 5]
//[]int
//5
//In main(), sli values: [10 2 3 4 5]
slice 切片
從上面的例子中可以看出slice作為參數傳遞的是指針,因此傳遞速度會快很多。
但是數組作為一個固定長度的數據類型,在使用中有很多不方便的地方,因此go提供了一個很類似python 中的list的數據類型slice
從名字也能看出來slice支持切片操作
sli := []int{1,2,3,4,5}
sli = sli[:3]
還支持append操作
sli = append(sli, 6)
sli = append(sli, sli2)
如果要實現類似數組的值傳遞的功能,可以利用 copy 函數
sli1 := make([]int, len(sli))
copt(sli1, sli)
初始化
- 可以通過make初始化
sli := make([]int, 5, 10) // 5 是其長度,10 是其容量(可選),分別可以通過 len(sli) cap(sli) 獲取
- 直接初始化(初始長度為0)
var sli []int // sli = nil
- 從數組或slice初始化
sli := arr[:] // sli 的修改也會影響到arr
對比
從上面的內容可以看出數組與切片有以下區別
- 數組定長,定義的時候就需要確定,切片不定長
- 切片支持append、copy、切片操作
- 數組作為參數的時候是默認進行拷貝,值傳遞,而切片是引用傳遞
順便說一下,slice的數據結構類似下面:
+--------------------+
| data pointer |
+--------------------+
| len |
+--------------------+
| cap |
+--------------------+
然后擴容方式與vector類似,1024字節以下是每次cap增加一倍,1024以上是每次cap增加1/4