go的切片擴容機制詳解
切片的擴容策略?如何擴容?
擴容策略:如果切片的容量小于 1024 個元素,于是擴容的時候就翻倍增加容量??側萘繌脑瓉淼?個翻倍到現(xiàn)在的2個。
一旦元素個數(shù)超過 1024 個元素,那么增長因子就變成 1.25 ,即每次增加原來容量的四分之一。
注意:擴容擴大的容量都是針對原來的容量而言的,而不是針對原來數(shù)組的長度而言的。
舉一個擴容策略例子:
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
從結果我們可以看出,新切片和之前的切片已經(jīng)不同了,因為新的切片更改了一個值,并沒有影響到原來的數(shù)組,新切片指向的數(shù)組是一個全新的數(shù)組,并且cap容量也發(fā)生了變化。
那么到底是新數(shù)組還是老數(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]
通過這個結果可以明顯的看出,修改新切片的值居然影響到了老切片的值了,擴容以后并沒有新建一個新的數(shù)組,并且append操作也改變了原來數(shù)組的值,如果原數(shù)組上有多個切片,那么這些切片都會影響,產(chǎn)生了莫名的bug!
這種情況也極容易出現(xiàn)在字面量創(chuàng)建切片時候,第三個參數(shù) cap 傳值的時候,如果用字面量創(chuàng)建切片,cap 并不等于指向數(shù)組的總容量,那么這種情況就會發(fā)生。
注意:建議用字面量創(chuàng)建切片的時候,cap 的值一定要保持清醒,避免共享原數(shù)組導致的 bug。
第二種情況:
第二種情況就是擴容策略的例子了,在擴容之后產(chǎn)生了新的切片,因為原數(shù)組的容量達到了最大值,再擴容都會開出一片新的內(nèi)存,把原來的值拷貝過來,再進行后續(xù)操作也不會影響原數(shù)組。
總結:時刻保持cap的清醒,推薦使用第二種情況的擴容策略
到此這篇關于go的切片擴容機制詳解的文章就介紹到這了,更多相關go 切片擴容 內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
相關文章
教你用go語言實現(xiàn)比特幣交易功能(Transaction)
每一筆比特幣交易都會創(chuàng)造輸出,輸出都會被區(qū)塊鏈記錄下來。給某個人發(fā)送比特幣,實際上意味著創(chuàng)造新的 UTXO 并注冊到那個人的地址,可以為他所用,今天通過本文給大家分享go語言實現(xiàn)比特幣交易功能,一起看看吧2021-05-05golang?gorm的預加載及軟刪硬刪的數(shù)據(jù)操作示例
這篇文章主要介紹了golang?gorm的預加載及軟刪硬刪的數(shù)據(jù)操作示例,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步早日升職加薪2022-04-04