golang Slice相關知識

2021-10-22 10:28:50 字數 2099 閱讀 6927

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...