Go slice那些事

今晚閑來無事,總結(jié)一下Go的slice

slice是什么
slice在Go中的原型?
slice類似數(shù)組,是一種定長的數(shù)組。在底層slice是這樣的:
type slice struct {
array unsafe.Pointer
len int
cap int
}

如何創(chuàng)建slice
1.創(chuàng)建nil slice
var lst []int

2.創(chuàng)建無容量的空slice
lst := make([]int, 0, 0)

3.創(chuàng)建有容量的空slice
lst := make([]int, 0, 6)

4.創(chuàng)建零值slice(10個0)
lst := make([]int, 10)

5.用引用創(chuàng)建slice
lst := array[:]

slice的其他操作函數(shù)
len(lst) 獲得slice的長度
cap(lst) 獲得slice的容量
append(lst, 6) 給lst添加1個數(shù)字6
append(lst, lst2…) 給lst添加一個slice,lst2是一個slice
copy(lst, srcList) //拷貝srcList中內(nèi)容到lst中去,僅能拷貝len(lst)個元素

部分細節(jié)陷阱
1.函數(shù)形參為slice
函數(shù)形參傳遞slice是值傳遞,并不是引用傳遞,在函數(shù)中修改形參的值,并不會影響函數(shù)外的傳入的slice
解決辦法
(1):傳入slice指針
func modify(lst *[]int) {
//修改lst
}

(2):函數(shù)內(nèi)修改了slice后返回
func modify(lst []int) []int {
//修改lst

return s

}

(3):將函數(shù)作為slice的指針
type sliceInt []int
func(this *sliceInt) modify() {
//修改lst
}

2.數(shù)據(jù)同源
func main() {
lst := [2]int{}
lst[0] = 1

fmt.Printf("lst: %v , len: %d, cap: %d\n", lst, len(lst), cap(lst))

dlst := lst[0:1]
dlst[0] = 5

fmt.Printf("lst: %v ,len: %d, cap: %d\n", lst, len(lst), cap(lst))
fmt.Printf("dlst: %v, len: %d, cap: %d\n", dlst, len(dlst), cap(dlst))

}

輸出如下
lst: [1 0] , len: 2, cap: 2
lst: [5 0] ,len: 2, cap: 2
dlst: [5], len: 1, cap: 2

原因:dlst會指向來源于lst,底層數(shù)據(jù)指針是指向lst的,修改dlst的數(shù)據(jù)也同時會修改lst的數(shù)據(jù)。

3.slice擴容陷阱
func main() {
lst := [2]int{}
lst[0] = 1

fmt.Printf("lst: %v , len: %d, cap: %d\n", lst, len(lst), cap(lst))

dlst := lst[0:1]
dlst = append(dlst, []int{2, 3}...)
dlst[1] = 1

fmt.Printf("lst: %v ,len: %d, cap: %d\n", lst, len(lst), cap(lst))
fmt.Printf("dlst: %v, len: %d, cap: %d\n", dlst, len(dlst), cap(dlst))

}

輸出如下:
lst: [1 0] , len: 2, cap: 2
lst: [1 0] ,len: 2, cap: 2
dlst: [1 1 3], len: 3, cap: 4

原因:因為存儲空間不夠,需要擴容,dlst會被分配新的空間,所以此時修改dlst數(shù)據(jù)并不會改變lst中的源數(shù)據(jù)。因為dlst數(shù)據(jù)指針已經(jīng)不再指向源數(shù)據(jù)地址。

Empty Slice和Nil Slice和零slice
1.零slice
lst := make([]int, 10)
10個零值slice

2.空Slice
lst := make([]int, 0)
沒有長度和容量的slice

3.nil Slice
var lst []int
此時lst是一個nil的slice,底層數(shù)據(jù) len:0,cap:0,*Elem:nil
注:可以對nil的slice 使用append操作。

擴容策略
append的擴容規(guī)則為:
1.如果新申請容量大于2倍的舊容量,最終容量就是新申請的容量;否則執(zhí)行第2步
2.如果舊切片的長度小于1024,則最終容量就是舊容量的兩倍,否則執(zhí)行第3步
3.如果舊切片長度大于等于1024,則最終容量從舊容量開始循環(huán)增加原來的 1/4,即直到最終容量大于等于新申請的容量
4.如果最終容量(cap)計算值溢出,則最終容量(cap)就是新申請容量(cap)

注:具體的代碼參考go目錄 src/runtime/slice.go中的growslice函數(shù)。

文章也同步發(fā)在了個人網(wǎng)站上
http://www.seabytelab.com/go-slice-lite.html

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容