go 切片和陣列
阿新 • • 發佈:2020-10-05
一、區別
陣列的長度是固定的,初始化後就不能修改長度,大家平時程式碼中比較少用。
slice是對陣列的一個封裝,可以動態擴容,slice是一個結構體,包含三個欄位:底層陣列、長度、容量
二、初始化方式
陣列
var a = [4]int{1,2,3,4} var b = [...]int{1,2,3,4,5}
切片
var a []int //當前值為nil,未分配記憶體空間 var b = []int{1, 2, 3} var c = make([]int, 5) //初始化5個元素,預設值為0,容量為5,在後面追加元素就會觸發擴容 var d = make([]int, 0, 5) //初始化0個元素,容量為5
注意:slice在追加元素時如果容量不夠會觸發擴容,原slice拷貝到新slice中,擴容規則網上的說法:原slice小於1024,新的slice容量變成原slice的2倍,大於1024時,新slice容量變成原slice的1.25倍。這裡的說法只是一個大概不是很準確,感興趣的朋友可以檢視網路上相關文章或原始碼,其實這對於我們平時開發影響不是很大,想要最求效能可以在初始化時預估容量,減少擴容和拷貝的次數。
三、拷貝
第一種
var a = []int{1,2,3,4,5} var b = a[2:4] //拷貝a中部分資料到b中 b[0] = 12 //改變b第一個元素的值log.Println(a,b) //輸出:[1 2 12 4 5] [12 4] 兩個陣列的值都被改變了,說明資料是地址拷貝 b = append(b,6,7,8,9) //追加元素,容量不夠引發擴容 b[0] = 13 //改變b第一個元素的值 log.Println(a,b) //輸出:[1 2 12 4 5] [13 4 6 7 8 9] b中的資料改變了,a中的值並沒有改變,擴容以後b和a中的元素已經沒有了關係
第二種
var a = []int{1,2,3,4,5} var b = make([]int,5) copy(b,a) //值拷貝 b[0] = 12 log.Println(a,b)//輸出:[1 2 3 4 5] [12 2 3 4 5]
四、平時使用需要注意的地方
1、作為函式引數傳遞(go語言的函式引數傳遞,只有值傳遞,沒有引用傳遞),但有時候我們會產生一些誤區,看看下面這個例子
func f(a []int){ a[0] = 12 a = append(a,6) } func main(){ var a = []int{1,2,3,4,5} f(a) log.Println(a) //輸出:[12 2 3 4 5] 第一個元素改變了,但值6並沒有追加到a中 }
2、range 中改變值
var a = []int{1, 2, 3, 4, 5} for _, v := range a { //不會改變a中元素的值(v只是一個臨時變數) v = v + 2 } log.Println(a) //輸出:[1 2 3 4 5] for i := range a { //會改變a中的值 a[i] = i + 2 } log.Println(a) //輸出:[2 3 4 5 6]
五、擴充套件
1、slice的結構
func main(){ var a = []int{1, 2, 3, 4, 5} s := (*SliceHeader)(unsafe.Pointer(&a)) log.Println(s.Len,s.Cap) //輸出:5 5 } type SliceHeader struct { Data uintptr //底層陣列地址 Len int //長度 Cap int //容量 }
2、append方法必須要有接收者
var a = []int{1, 2, 3, 4, 5} append(a,6) //編譯失敗
3、陣列的元素在記憶體中地址是連續的
var a = []int{1, 2, 3, 4, 5} s := (*reflect.SliceHeader)(unsafe.Pointer(&a)) //根據陣列索引獲取元素值 arrGet := func(n int)int{ if n >= s.Len{ panic("索引越界") } v := (*int)(unsafe.Pointer(uintptr(unsafe.Pointer(s.Data))+unsafe.Sizeof(int(0))*uintptr(n))) return *v } log.Println(arrGet(0)) //輸出:1 log.Println(arrGet(1)) //輸出:2 log.Println(arrGet(5)) //輸出:panic: 索引越界
以上內容為個人理解,如有問題歡迎指出。