slice 又稱動態陣列,依託陣列實現,可以方便的進行擴容、傳遞等,實際使用中比陣列更靈活。slice依託陣列實現,底層陣列對使用者遮蔽,在底層陣列容量不足時可以實現自動重分配並生成新的slice。 接下來按照實際使用場景分別介紹其實現機制。
宣告和初始化變數切片主要有以下幾種:
內建函式len( )和cap( )分別用於查詢切片的長度和容量,這兩個操作的時間複雜度均為o(1)。
原始碼包中src/runtime/slice.go:slice定義了slice的資料結構:
type slice struct
從資料結構看slice很清晰, array指標指向底層陣列,len表示切片長度,cap表示底層陣列容量。
1)使用make( )建立slice
使用make來建立slice時,可以同時指定長度和容量,建立時底層會分配乙個陣列,陣列的長度即容量。
例如,語句slice := make(int, 5, 10)所建立的slice,結構如下圖所示:
該slice長度為5,即可以使用下標slice[0] ~ slice[4]來操作裡面的元素,capacity為10,表示後續向slice新增新的元素時可以不必重新分配記憶體,直接使用預留記憶體即可。
2)使用陣列建立slice
使用陣列來建立slice時,slice將與原陣列共用一部分記憶體。
例如,語句slice := array[5:7]所建立的slice,結構如下圖所示:
陣列和切片操作可能作用於同一塊記憶體,這也是使用過程中需要注意的地方。
3)slice擴容
例如,當向乙個capacity為5,且length也為5的slice再次追加1個元素時,就會發生擴容,如下圖所示:
擴容容量的選擇遵循以下規則:
假如slice容量夠用,則將新元素追加進去,slice.len++,返回原slice
原slice容量不夠,則將slice先擴容,擴容後得到新slice
將新元素追加進新slice,slice.len++,返回新的slice。
使用copy()內建函式拷貝兩個切片時,會將源切片的資料逐個拷貝到目的切片指向的陣列中,拷貝數量取兩個切片長度的最小值。
例如長度為10的切片拷貝到長度為5的切片時,將會拷貝5個元素。
也就是說,copy過程中不會發生擴容。
5)特殊切片
跟據陣列或切片生成新的切片一般使用slice := array[start:end]
方式,這種新生成的切片並沒有指定切片的容量,實際上新切片的容量是從start開始直至array的結束。
slicea :=
make([
]int,5
,10)sliceb := slicea[0:
5]
根據陣列或切片生成切片還有另一種寫法,即切片同時也指定容量,即slice[start:end:cap], 其中cap即為新切片的容量,當然容量不能超過原切片實際值,如下所示:
slicea :=
make([
]int,5
,10)//length = 5; capacity = 10
sliceb := slicea[0:
5]//length = 5; capacity = 10
slicec := slicea[0:
5:5]
//length = 5; capacity = 5
這切片方法不常見,在golang原始碼裡能夠見到,不過非常利於切片的理解。 golang slice效能分析
golang在gc這塊的做得比較弱,頻繁地申請和釋放記憶體會消耗很多的資源。另外slice使用陣列實現,有乙個容量和長度的問題,當slice的容量用完再繼續新增元素時需要擴容,而這個擴容會把申請新的空間,把老的內容複製到新的空間,這是乙個非常耗時的操作。有兩種方式可以減少這個問題帶來的效能開銷 在s...
Golang slice 的底層實現
首先我們來看段 的輸出 s make int,4 for i 0 i 4 i s0 s 0 fmt.println s 輸出的結果是 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 帶著這些疑問,我們來看看slice的底層實現。slice的結構 type slice structar...
golang slice 原始碼解讀
本文從原始碼角度學習 golang slice 的建立 擴容,深拷貝的實現。slice 僅有三個字段,其中array 是儲存資料的部分,len 欄位為長度,cap 為容量。type slice struct通過下面 可以輸出空slice 的大小 package main import fmt imp...