GO 切片實力踩坑

2021-10-08 05:52:45 字數 2372 閱讀 1398

go 語言的切片這兩天用了用, 可以支援切割陣列的中間部分. 但今天使用中, 出了 bug, 查了半天, 發現是切片的問題, 簡單寫個 demo 復現當時的情況:

package main

import

"fmt"

func

main()

b := a[2:

4]b[0]=

9 fmt.

println

(a)}

你以為輸出的是什麼? 來, 看結果:

[1 2 9 4 5]

懵沒懵?? 這是怎麼回事呢?

(我用個語言怎麼老踩坑, 笨的一x)

看這段 go **的輸出, 我們在修改b陣列第乙個元素值的時候,a陣列的第三個元素修改了, 這兩個有什麼聯絡嗎? 仔細看,b陣列在切的時候, 切的不就是a陣列第三第四的元素嗎? 如此看來,b[0]不正對應a[2]嗎?

大膽假設: **go 中對陣列進行切割, 並不會切乙個新的陣列出來, 而是仍然使用原陣列, 只是修改下陣列的首位址和長度. **

驗證:

package main

import

"fmt"

func

main()

b := a[2:

4]b[0]=

9 fmt.

printf

("%p\n"

,&a[2]

) fmt.

printf

("%p\n"

,&b[0]

)}

列印出來的位址完全一致, 印證了之前的猜想, 果然是乙個陣列. 同時修改a陣列, 也會影響到b陣列.

那可不可以對b陣列越界訪問, 訪問a陣列的值呢? 不行, go 會對陣列進行越界檢查.

檢視文件後發現, go 切片的內部實現是這樣的包含了三個欄位. 其中各欄位含義如下:

陣列首位址指標: 指向底層陣列的首位址(這個是真正的陣列)

陣列長度: 陣列當前已經使用的長度

陣列容量: 陣列已分配記憶體的總長度, 比陣列長度多出的部分, 是占用記憶體還沒有使用的.

如此看來, 對其進行切割, 並不會整個複製, 對於大切片的操作就顯得很友好了, 畢竟共享底層陣列, 只需要建立很少的資料就可以了. 只是要注意陣列的同步修改問題.

這麼看來, 貌似也可以解釋為什麼叫切片了. **切片就是將底層的陣列切出一部分來, 而不會建立新的陣列. **

切片是有容量的, 那上面的切片b的容量是多少呢? 我看了一下: 長度是2, 容量是3.

go 的切片在容量足夠的時候, 是不會動態擴容的. (擴容會建立更大容量新的陣列並複製原陣列資料). 那也就是說, 如果我向b追加資料, 就可以影響到原陣列的後面的資料了??

試一發:

package main

import

"fmt"

func

main()

b := a[2:

4]b =

(b,10

) fmt.

println

(b) fmt.

println

(a)}

果然, 容量允許的話, 追加操作使用的仍然是原始陣列.

所以:切片的容量其實是底層陣列的容量

同時, 有了之前對 go 的了解, 知道 go 所有的函式都是以傳遞副本值的方式進行, 傳遞切片也一樣, 而切片的結構體包含(陣列指標, 長度, 容量)三個元素, 底層陣列並不屬於值本身, 所以切片在函式間傳遞的複製成本很小, 而且函式對切片的修改也會反應到底層陣列上. 同理可得, 如果在函式中對切片執行了擴容操作, 那改動就不會影響原資料, 因為擴容後操作的是新的陣列了.

ok. 切片到這裡就結束了, 簡單說就是陣列上面再套一層. 切片的切片共享底層陣列.

最後說一句, go 建立陣列和切片的方式(陣列和切片是不同的資料結構):

// 方括號為空, 建立的是切片型別

a :=

int// 方括號指定長度, 建立的是真正的陣列型別

b :=[2

]int

至此, 對 go 的切片有了全新的認識. 在使用切片的時候, 需要特別注意, 切片的擷取與原物件共享底層陣列, 在資料修改時要特別注意.

如果需要乙個安全的可修改的切皮, 可以使用copy函式複製乙個全新的陣列出來, 與原陣列分離就可以了.

GO 切片實力踩坑

go 語言的切片這兩天用了用,可以支援切割陣列的中間部分.但今天使用中,出了 bug,查了半天,發現是切片的問題,簡單寫個 demo 復現當時的情況 package main import fmt func main b a 2 4 b 0 9 fmt.println a 你以為輸出的是什麼?來,看...

go學習踩坑實錄

對於query而言,沒有資料是不會返回error,同時sql.rows也沒有返回關於長度的屬性,因此只能自己遍歷rows屬性,這是比較操蛋的事情,對比而言queryrow就相對於友好一點,如果沒有返回結果,error的值會是sql.errnorows,因此,判斷這個值就能得到資料庫中是否有我們需要的...

Go 切片使用繞坑指南

不知道大家有沒有發現在乙個函式內部對切片引數進行了排序後也會改變函式外部原來的切片中元素的順序,但是在函式內向切片增加了元素後在函式外的原切片卻沒有新增元素,更奇怪的是新增並排序後,外部的切片有可能元素數量和元素順序都不會變,這是為什麼呢?我們通過三個小測驗來解釋造成這個現象的原因。下面的 的輸出什...