最近閒來無事,深入研究了slice在golang中的實現並簡要閱讀了其相關的底層實現**後,對於實際工作中的一些slice相關**的寫法與bug有了一種豁然開朗的感覺。故記錄下來,與君分享。
陣列 vs 切片
對於初學者來說,我們必須分清楚陣列與切片的區別。
在go中,陣列與其他語言並無太大區別,都是一段指定長度的連續記憶體空間。例如如下**,我們宣告乙個長度為4,型別為int
的陣列a
。
var a [4]int
此時,go會呼叫mallocgc
函式為我們申請一段連續的記憶體空間,如下圖所示。
而對於slice,其實際上是一種結構體,基於陣列的一種抽象,相當於其他語言中的動態陣列。
切片的表示
在runtime
包中,切片的定義如下。
type slice struct
array
屬性指向乙個底層陣列,實際資料儲存在其中,對於同乙個底層陣列,其可以被多個切片引用。
len
屬性限制了切片的長度,通過array
與len
屬性,我們就能劃分出陣列上的一段資料。
cap
屬性表示切片的容量,其以array
所指向的位址為起始位置,陣列末尾為結束位置。兩者之間的跨度即為cap
的大小。
舉例說明,這裡我們建立乙個切片。
s1 := make(byte, 4, 6)
s1[0] = 'a'
s1[1] = 'b'
s1[2] = 'c'
s1[3] = 'd'
其在記憶體中表示如下所示。
此時,我們再建立乙個切片s2 := s1[1:3]
。其表示如下所示。
由於s2是基於s1傳建的,因此其指向了同一底層陣列,不同的是,s2的array
指向的是b
元素的起始記憶體位址。顯而易見,當我們執行s1[1] = 'x'
語句時,s2[0]
的值也會被改變為x
。
空切片 vs nil切片
nil切片var s byte
,如下圖所示。
空切片s := make(byte, 0)
,如下圖所示。
nil切片array
屬性為nil,而空切片array
屬性為空陣列的位址。
切片的擴容
首先,要明確,擴容針對的是切片的容量而非底層陣列的實際長度!
顯然,s1[4]
的值也會因此而被改變為e
。
切片**編寫建議
在實際工作中,針對切片操作,我們應該注意哪些呢?
及時釋放大切片。例如下述**
for i := 0; i < 3; i++
雖然我們只使用了tmp的前10個位元組,但是其指向的底層陣列依然是原來tmp指向的大陣列,因此gc不會**該大陣列,從而導致記憶體占用過大。為了避免此問題,我們可以建立乙個小切片,然後將前10個位元組複製過去,如下**所示。
for i := 0; i < 3; i++
使用for range
語句時,例如
for i, name := range names
其中name
變數是值拷貝,每一次迭代都將對應i
位置上的值拷貝到變數name
上,因此你無法通過改變name
的值來改變切片names
對應位置上的值。當然,我們都知道在迭代中修改原切片是十分不好的程式設計習慣。
參考
go語言 slice 迭代slice
go語言內建乙個關鍵字range用於迭代集合,當然他也可以迭代slice,也可以使用 來忽略我們不關心的元素,但是如果只關心index則不需這麼寫 for index,range slice1。下在給出完整 package main import fmt func main for index,va...
Go語言切片 Slice
python裡面切片是一種操作,用於取list裡面元素。而go語言的切片則是一種資料型別,而不是一種操作。go語言中提供了切片 slice 作為一種更為靈活 功能強悍的內建型別,它其實是陣列的一種抽象。切片的原始碼 type slice struct slice是原陣列在記憶體中的位址的乙個指標,它...
go 陣列與slice的區別
總結 2.相同大小陣列可以賦值,會拷貝全部內容。slice賦值和指標一樣。陣列和slice之間不能相互賦值。當然slice有自己的copy函式 3.陣列也可以進行切片,返回值是乙個slice,改變slice時會同步修改陣列內容,相當於取得了這個陣列的指標 測試 陣列定義方式 1 寫明長度 c1 5 ...