go的切片擴(kuò)容機(jī)制詳解
切片的擴(kuò)容策略?如何擴(kuò)容?
擴(kuò)容策略:如果切片的容量小于 1024 個(gè)元素,于是擴(kuò)容的時(shí)候就翻倍增加容量???cè)萘繌脑瓉?lái)的1個(gè)翻倍到現(xiàn)在的2個(gè)。
一旦元素個(gè)數(shù)超過(guò) 1024 個(gè)元素,那么增長(zhǎng)因子就變成 1.25 ,即每次增加原來(lái)容量的四分之一。
注意:擴(kuò)容擴(kuò)大的容量都是針對(duì)原來(lái)的容量而言的,而不是針對(duì)原來(lái)數(shù)組的長(zhǎng)度而言的。
舉一個(gè)擴(kuò)容策略例子:
func main() {
? ? slice := []int{10, 20, 30, 40}
? ? newSlice := append(slice, 50)
? ? fmt.Printf("Before slice = %v, Pointer = %p, len = %d, cap = %d\n", slice, &slice, len(slice), cap(slice))
? ? fmt.Printf("Before newSlice = %v, Pointer = %p, len = %d, cap = %d\n", newSlice, &newSlice, len(newSlice), cap(newSlice))
? ? newSlice[1] += 10
? ? fmt.Printf("After slice = %v, Pointer = %p, len = %d, cap = %d\n", slice, &slice, len(slice), cap(slice))
? ? fmt.Printf("After newSlice = %v, Pointer = %p, len = %d, cap = %d\n", newSlice, &newSlice, len(newSlice), cap(newSlice))
}
// result?
Before slice = [10 20 30 40], Pointer = 0xc4200b0140, len = 4, cap = 4
Before newSlice = [10 20 30 40 50], Pointer = 0xc4200b0180, len = 5, cap = 8
After slice = [10 20 30 40], Pointer = 0xc4200b0140, len = 4, cap = 4
// 相加的數(shù)是在新的切片上相加的
After newSlice = [10 30 30 40 50], Pointer = 0xc4200b0180, len = 5, cap = 8從結(jié)果我們可以看出,新切片和之前的切片已經(jīng)不同了,因?yàn)樾碌那衅牧艘粋€(gè)值,并沒(méi)有影響到原來(lái)的數(shù)組,新切片指向的數(shù)組是一個(gè)全新的數(shù)組,并且cap容量也發(fā)生了變化。
那么到底是新數(shù)組還是老數(shù)組呢?
擴(kuò)容之后數(shù)組就一定是新的嗎?其實(shí)是分兩種情況。
第一種情況:
func main() {
? ? array := [4]int{10, 20, 30, 40}
? ? slice := array[0:2]
? ? newSlice := append(slice, 50)
? ? fmt.Printf("Before slice = %v, Pointer = %p, len = %d, cap = %d\n", slice, &slice, len(slice), cap(slice))
? ? fmt.Printf("Before newSlice = %v, Pointer = %p, len = %d, cap = %d\n", newSlice, &newSlice, len(newSlice), cap(newSlice))
? ? newSlice[1] += 10
? ? fmt.Printf("After slice = %v, Pointer = %p, len = %d, cap = %d\n", slice, &slice, len(slice), cap(slice))
? ? fmt.Printf("After newSlice = %v, Pointer = %p, len = %d, cap = %d\n", newSlice, &newSlice, len(newSlice), cap(newSlice))
? ? fmt.Printf("After array = %v\n", array)
}
// result
? ? Before slice = [10 20], Pointer = 0xc4200c0040, len = 2, cap = 4
? ? Before newSlice = [10 20 50], Pointer = 0xc4200c0060, len = 3, cap = 4
? ? After slice = [10 30], Pointer = 0xc4200c0040, len = 2, cap = 4
? ? After newSlice = [10 30 50], Pointer = 0xc4200c0060, len = 3, cap = 4
? ? After array = [10 30 50 40]通過(guò)這個(gè)結(jié)果可以明顯的看出,修改新切片的值居然影響到了老切片的值了,擴(kuò)容以后并沒(méi)有新建一個(gè)新的數(shù)組,并且append操作也改變了原來(lái)數(shù)組的值,如果原數(shù)組上有多個(gè)切片,那么這些切片都會(huì)影響,產(chǎn)生了莫名的bug!
這種情況也極容易出現(xiàn)在字面量創(chuàng)建切片時(shí)候,第三個(gè)參數(shù) cap 傳值的時(shí)候,如果用字面量創(chuàng)建切片,cap 并不等于指向數(shù)組的總?cè)萘浚敲催@種情況就會(huì)發(fā)生。
注意:建議用字面量創(chuàng)建切片的時(shí)候,cap 的值一定要保持清醒,避免共享原數(shù)組導(dǎo)致的 bug。
第二種情況:
第二種情況就是擴(kuò)容策略的例子了,在擴(kuò)容之后產(chǎn)生了新的切片,因?yàn)樵瓟?shù)組的容量達(dá)到了最大值,再擴(kuò)容都會(huì)開(kāi)出一片新的內(nèi)存,把原來(lái)的值拷貝過(guò)來(lái),再進(jìn)行后續(xù)操作也不會(huì)影響原數(shù)組。
總結(jié):時(shí)刻保持cap的清醒,推薦使用第二種情況的擴(kuò)容策略
到此這篇關(guān)于go的切片擴(kuò)容機(jī)制詳解的文章就介紹到這了,更多相關(guān)go 切片擴(kuò)容 內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Go語(yǔ)言編程學(xué)習(xí)golang配置golint
這篇文章主要為大家介紹了Go語(yǔ)言編程學(xué)習(xí)golang配置golint的過(guò)程示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2021-11-11
Golang使用gin模板渲染base64圖片出現(xiàn)#ZgotmplZ的解決辦法
這篇文章主要介紹了Golang使用gin模板渲染base64圖片出現(xiàn)#ZgotmplZ的的場(chǎng)景復(fù)現(xiàn)和解決辦法,文中通過(guò)代碼示例講解的非常詳細(xì),對(duì)大家解決問(wèn)題有一定的幫助,需要的朋友可以參考下2024-05-05
使用go的interface案例實(shí)現(xiàn)多態(tài)范式操作
這篇文章主要介紹了使用go的interface案例實(shí)現(xiàn)多態(tài)范式操作,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2020-12-12
淺談Go語(yǔ)言中的結(jié)構(gòu)體struct & 接口Interface & 反射
下面小編就為大家?guī)?lái)一篇淺談Go語(yǔ)言中的結(jié)構(gòu)體struct & 接口Interface & 反射。小編覺(jué)得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2017-07-07
GoFrame框架gset交差并補(bǔ)集使用實(shí)例
這篇文章主要為大家介紹了GoFrame框架gset交差并補(bǔ)集使用實(shí)例,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-06-06
Golang實(shí)現(xiàn)DFA算法對(duì)敏感詞過(guò)濾功能
DFA算法是確定性有限自動(dòng)機(jī),其特征是,有一個(gè)有限狀態(tài)集合和一些從一個(gè)狀態(tài)通向另一個(gè)狀態(tài)的邊,每條邊上標(biāo)記有一個(gè)符號(hào),通俗的講DFA算法就是把你要匹配的做成一顆字典樹(shù),然后對(duì)你輸入的內(nèi)容進(jìn)行匹配的過(guò)程,本文將利用DFA算法實(shí)現(xiàn)敏感詞過(guò)濾,需要的可以參考一下2023-10-10
淺談go-restful框架的使用和實(shí)現(xiàn)
這篇文章主要介紹了淺談go-restful框架的使用和實(shí)現(xiàn),小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2018-03-03

