一、切片:
Go 語言切片Slice是對數組的抽象,是引用類型。
Go 數組的長度不可改變,在特定場景中這樣的集合就不太適用,Go 中提供了一種靈活,功能強悍的內置類型切片("動態數組")。
與數組相比,切片的長度是不固定的,可以追加元素,在追加時可能使切片的容量增大。
[5]int
是數組,而 []int
是切片。
切片的數據結構中,包含一個指向數組的指針
array
,當前長度
len
,以及最大容量
cap
。
在使用
make([]int, len)
創建切片時,實際上還有第三個可選參數
cap
,也即
make([]int, len, cap)
。
在不聲明
cap
的情況下,默認
cap=len
。
當切片長度沒有超過容量時,對切片新增數據,不會改變
array
指針的值。
二、切片擴容
- 當原切片長度小於1024時,新切片的容量會直接翻倍。
- 而當原切片的容量大於等於1024時,會反復地增加25%,直到新容量超過所需要的容量。
- 當需要的容量超過原切片容量的兩倍時,會使用需要的容量作為新容量。
三、定義切片
1.聲明var定義一個nil的切片。
var tmp []int
2.使用make定義一個指定長度的切片
var tmp []int = make([]int ,10)
3.使用推導式
tmp := make([]int, 10)
4.也可以指定容量,其中 capacity 為可選參數。
tmp make([]T, length, capacity)
注意:nil切片和空切片的區別
nil切片:
// 創建 nil 整型切片
var myNum []int
空切片:
// 使用 make 創建空的整型切片 myNum := make([]int, 0) // 使用切片字面量創建空的整型切片 myNum := []int{}
無論是nil切片,還是空切片,都可以使用append, copy等方法。
無論是nil切片,還是空切片,都可以使用len(),他們的長度都是0。
要注意的是nil切片 == nil,但是 空切片 != nil。
四、切片初始化
s :=[] int {1,2,3 }
s := arr[:]
五、切片操作
1.append
s1 := []int{1, 2, 3, 4, 5} //短操作符聲明 len為4,cap為4 s2 := make([]int, 2, 4) //make語法聲明 ,len為2,cap為4 s3 := append(s2, 7) //append一個元素 s4 := append(s2, s1...) //append 一個切片所有的元素
2.copy
copy(s1, s2) // 復制,用s2的元素填充s1里去,改變原slice,覆蓋對應的key
3.刪除一個元素
//刪除第三個元素
s7 := append(s1[:1], s1[3:]...)
4.修改
// 修改原始數據的第一個元素
s7[0] = 999
5.遍歷
// 切片遍歷 var arr [5]int = [...]int{10,20,30,40,50} slice := arr[1:4] // for循環方式 for i := 0; i < len(slice); i++ { fmt.Printf("slice[%v]=%v", i, slice[i]) } fmt.Println() // for range方式 for index, value := range slice { fmt.Printf("i=%v v=%v\n", index, value) }
6.
sli := slice[:] // 引用一個切片
slice = slice[:0] // 清空一個切片
六、切片的幾個坑
由於切片是引用類型,不是值類型。類似於py的列表,也是引用類型。
第一個坑:子切片和父切片用的是同一個底層數組
pSlice := []int{0, 10, 20, 30, 40} //新建一個子切片,指定元素為pSlice的index 1到3(不包括3),即{10, 20} subSlice := pSlice[1:3] //這時候,改變subSlice的值,也會改動到pSlice subSlice[1] = 22 fmt.Println(pSlice) //{0, 10, 22, 30, 40} fmt.Println(subSlice) //{10, 22}
append,同樣會產生這樣的問題。
//append操作會返回一個新切片,同樣共享底層數組 subSlice = append(subSlice, 33) 這時候兩個slice的值如下: pSlice //{0, 10, 22, 33, 40} subSlice //{10, 22, 33}
第二個坑:for range遍歷的是副本