切片 Go語言切片是一種建立在數組類型之上的抽象,它構建在數組之上並且提供更強大的能力和便捷。解決了數組長度不可變等缺陷 聲明切片 切片的數據結構非常小,只有三個欄位:指向底層數組的指針,切片長度,切片容量。切片長度是指切片的真實長度,切片容量是指切片可擴展的最大長度,一般來講切片長度要小於 ...
切片
Go語言切片是一種建立在數組類型之上的抽象,它構建在數組之上並且提供更強大的能力和便捷。解決了數組長度不可變等缺陷
聲明切片
切片的數據結構非常小,只有三個欄位:指向底層數組的指針,切片長度,切片容量。切片長度是指切片的真實長度,切片容量是指切片可擴展的最大長度,一般來講切片長度要小於等於底層數組的長度也就是切片容量
cap()
用來計算切片容量,len()
用來計算切片長度,所以有0 <= len() <= cap()
var 切片名 + [] + 數據類型
(聲明切片但不初始化,那麼這個切片的預設值為nil,長度為 0)
var slice []int
slice := make([]數據類型,切片長度,切片容量)
(使用make()來聲明切片)
// 聲明一個長度為10,容量為20的切片slice
slice := make([]int, 10, 20)
// 因為切片長度為10 所以只能訪問10個元素,剩下的10個需要進行切片擴容之後才能使用
slice := []數據類型{初始化}
// 聲明時初始化
slice := []int{0,1,2,3,4,5,6,7,8,9}
// 同數組一樣,切片也可以對單一元素賦值
slice := []int{3:9,5:10}
- 基於現有的數組或切片,創建切片
// 創建底層數組array
array := [10]int{0,1,2,3,4,5,6,7,8,9}
// 以array 為底層數組創建切片slice,切片從索引3開始到索引9結束(並不包括索引9)
slice := array[3,9]
// 輸出slice的長度和容量
fmt.Printf("切片長度:%d\n", len(slice)) // 6
fmt.Printf("切片容量:%d\n", cap(slice)) // 7
// slice := array[i,j]
// 切片長度(j-i):9 - 3 = 6
// 切片容量(底層數組長度 - i):10 - 3 = 7
// 也可以直接限制切片容量
slice := array[2,9,7]
fmt.Printf("切片長度:%d\n", len(slice)) // 7
fmt.Printf("切片容量:%d\n", cap(slice)) // 7
切片使用
使用切片,和使用數組一樣,通過索引就可以獲取切片對應元素的值,同樣也可以修改對應元素的值
arr := [...]int{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}
slice := arr[3:9]
slice[3] = 100
fmt.Println(arr) // [0 1 2 3 4 5 100 7 8 9]
⭐:因為切片是對部分底層數組的引用,所以修改切片的值,實際上是修改切片對應底層數組的值
遍歷切片(for range)
arr := [...]int{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}
slice := arr[3:9]
// i:切片下標 j: 下標對應的值
for i, j := range slice {
fmt.Printf("%d : %d \n", i, j)
}
擴展切片
直接擴展slice = slice[0 : len(slice)+1]
切片可以反覆擴展直到占據整個相關數組,但是不能超過相關數組長度!!!!!
arr := [...]int{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}
slice := arr[3:8]
fmt.Printf("slice長度:%d\n", len(slice))// 5
fmt.Printf("slice容量:%d\n", cap(slice))// 7
for i, j := range slice {
fmt.Printf("%d : %d \n", i, j)
}
slice = slice[0 : len(slice)+1]
fmt.Printf("slice長度:%d\n", len(slice))// 6
fmt.Printf("slice容量:%d\n", cap(slice))// 7
for i, j := range slice {
fmt.Printf("%d : %d \n", i, j)
}
append擴展
arr := [...]int{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}
for i := range arr {
fmt.Printf("arr[%d]: %p\n", i, &arr[i])
}// 0xc0000ac0f0 ~~ 0xc0000ac138
// 在以arr為底層數組創建切片slice,切片內元素的地址與數組內元素地址相同
slice := arr[3:9]
fmt.Printf("slice長度:%d\n", len(slice))// 6
fmt.Printf("slice容量:%d\n", cap(slice))// 7
for i := range slice {
fmt.Printf("slice[%d]: %p\n", i, &slice[i])
}// 0xc0000ac108 ~~ 0xc0000ac130
// 使用append()在arr後面擴展一位,保持切片長度仍小於切片容量,切片內元素的地址與數組內元素地址依舊相同,切片長度加一,切片容量不變
newSlice1 := append(slice, 9)
fmt.Printf("newSlice1長度:%d\n", len(newSlice1))// 7
fmt.Printf("newSlice1容量:%d\n", cap(newSlice1))// 7
for i := range newSlice1 {
fmt.Printf("newSlice1[%d]: %p\n", i, &newSlice1[i])
}// 0xc0000ac108 ~~ 0xc0000ac138
// 使用append()在arr後面擴展三位,導致切片長度大於原來的切片容量,切片內元素的地址與數組內元素地址完全不同,切片長度加三,切片容量翻倍
newSlice2 := append(slice, 9, 10, 11)
fmt.Printf("newSlice2長度:%d\n", len(newSlice2))// 9
fmt.Printf("newSlice2容量:%d\n", cap(newSlice2))// 14
for i := range newSlice2 {
fmt.Printf("newSlice2[%d]: %p\n", i, &newSlice2[i])
}// 0xc0000d4000 ~~ 0xc0000d4040
⭐:當切片擴展時,切片長度大於原切片的切片容量,就會新建一個底層數組,把原來數組的值複製到新底層數組裡,再追加新值,這時候就不會影響原來的底層數組了。append
函數會智能的增長底層數組的容量,目前的演算法是:容量小於1000個時,總是成倍的增長,一旦容量超過1000個,增長因數設為1.25,也就是說每次會增加25%的容量