淺談Golang 切片(slice)擴(kuò)容機(jī)制的原理
我們知道 Golang 切片(slice) 在容量不足的情況下會(huì)進(jìn)行擴(kuò)容,擴(kuò)容的原理是怎樣的呢?是不是每次擴(kuò)一倍?下面我們結(jié)合源碼來(lái)告訴你答案。
一、源碼
Version : go1.15.6 src/runtime/slice.go
//go1.15.6 源碼 src/runtime/slice.go func growslice(et *_type, old slice, cap int) slice { //省略部分判斷代碼 //計(jì)算擴(kuò)容部分 //其中,cap : 所需容量,newcap : 最終申請(qǐng)容量 newcap := old.cap doublecap := newcap + newcap if cap > doublecap { newcap = cap } else { if old.len < 1024 { newcap = doublecap } else { // Check 0 < newcap to detect overflow // and prevent an infinite loop. for 0 < newcap && newcap < cap { newcap += newcap / 4 } // Set newcap to the requested cap when // the newcap calculation overflowed. if newcap <= 0 { newcap = cap } } } //省略部分判斷代碼 }
二、原理
1. 如果當(dāng)前所需容量 (cap) 大于原先容量的兩倍 (doublecap),則最終申請(qǐng)容量(newcap)為當(dāng)前所需容量(cap);
2. 如果<條件1>不滿足,表示當(dāng)前所需容量(cap)不大于原容量的兩倍(doublecap),則進(jìn)行如下判斷;
3. 如果原切片長(zhǎng)度(old.len)小于1024,則最終申請(qǐng)容量(newcap)等于原容量的兩倍(doublecap);
4. 否則,最終申請(qǐng)容量(newcap,初始值等于 old.cap)每次增加 newcap/4,直到大于所需容量(cap)為止,然后,判斷最終申請(qǐng)容量(newcap)是否溢出,如果溢出,最終申請(qǐng)容量(newcap)等于所需容量(cap);
這樣說(shuō)大家可能不太明白,來(lái)幾個(gè)例子:
2.1 實(shí)例1
驗(yàn)證條件1:
package main import "fmt" func main() { //第1條中的例子: var slice = []int{1, 2, 3} var slice1 = []int{4, 5, 6, 7, 8, 9, 10, 11, 12} fmt.Printf("slice %v len = %v cap = %v\n", slice, len(slice), cap(slice)) fmt.Printf("slice1 %v len = %v cap = %v\n", slice1, len(slice1), cap(slice1)) slice = append(slice, slice1...) fmt.Printf("slice %v len = %v cap = %v\n", slice, len(slice), cap(slice)) }
輸出:
[root@localhost test]# go run main.go
slice [1 2 3] len = 3 cap = 3
slice1 [4 5 6 7 8 9 10 11 12] len = 9 cap = 9
slice [1 2 3 4 5 6 7 8 9 10 11 12] len = 12 cap = 12
[root@localhost test]#
在實(shí)例1中,所需容量 cap = 9+3 = 12,原容量的兩倍 doublecap = 2 * 3 = 6,滿足 <條件1> 即:所需容量大于原容量的兩倍,所以最終申請(qǐng)容量 newcap = cap = 12。
2.2 實(shí)例2
驗(yàn)證條件2,3:
package main import "fmt" func main() { //第2、3條中的例子: var slice = []int{1, 2, 3, 4, 5, 6, 7} var slice1 = []int{8, 9} fmt.Printf("slice %v len = %v cap = %v\n", slice, len(slice), cap(slice)) fmt.Printf("slice1 %v len = %v cap = %v\n", slice1, len(slice1), cap(slice1)) slice = append(slice, slice1...) fmt.Printf("slice %v len = %v cap = %v\n", slice, len(slice), cap(slice)) }
輸出:
[root@localhost test]# go run main.go
slice [1 2 3 4 5 6 7] len = 7 cap = 7
slice1 [8 9] len = 2 cap = 2
slice [1 2 3 4 5 6 7 8 9] len = 9 cap = 14
[root@localhost test]#
在實(shí)例2中,所需容量 cap = 7+2 = 9,原容量的兩倍 doublecap = 2*7 = 14,原切片長(zhǎng)度 old.len = 7,滿足 <條件2,3>,即: 所需容量小于原容量的兩倍,并且原切片長(zhǎng)度 old.len 小于1024,所以,最終申請(qǐng)容量 newcap = doublecap = 14。
2.3 實(shí)例3
驗(yàn)證條件4:
package main import "fmt" func main() { //第2條中的例子: var slice []int for i := 0; i < 1024; i++ { slice = append(slice, i) } var slice1 = []int{1024, 1025} fmt.Printf("slice %v len = %v cap = %v\n", slice, len(slice), cap(slice)) fmt.Printf("slice1 %v len = %v cap = %v\n", slice1, len(slice1), cap(slice1)) slice = append(slice, slice1...) fmt.Printf("slice %v len = %v cap = %v\n", slice, len(slice), cap(slice)) }
輸出:
[root@localhost test]# go run main.go
slice [0 1 2 3 4 5 6……1017 1018 1019 1020 1021 1022 1023] len = 1024 cap = 1024
slice1 [1024 1025] len = 2 cap = 2
slice [0 1 2 3 4 5 6……1017 1018 1019 1020 1021 1022 1023 1024 1025] len = 1026 cap = 1280
[root@localhost test]#
在實(shí)例3中,所需容量 cap = 1024+2 = 1026,doublecap = 2048, old.len = 1024,滿足 <條件4> ,所以,newcap = 1024 + 1024/4 = 1280。
到此這篇關(guān)于淺談Golang 切片(slice)擴(kuò)容機(jī)制的原理的文章就介紹到這了,更多相關(guān)Golang 切片擴(kuò)容機(jī)制內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Go語(yǔ)言字符串及strings和strconv包使用實(shí)例
字符串是工作中最常用的,值得我們專門的練習(xí)一下,下面這篇文章主要給大家介紹了關(guān)于Go語(yǔ)言字符串及strings和strconv包使用的相關(guān)資料,文中通過(guò)代碼介紹的非常詳細(xì),需要的朋友可以參考下2024-06-06Go標(biāo)準(zhǔn)庫(kù)http?server的優(yōu)雅關(guān)閉深入理解
這篇文章主要為大家介紹了Go標(biāo)準(zhǔn)庫(kù)http?server的優(yōu)雅有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪關(guān)閉深入理解2024-01-01解決GO編譯時(shí)避免引入外部動(dòng)態(tài)庫(kù)的問(wèn)題
最近碰到一個(gè)問(wèn)題,有一個(gè)流量采集的組件中使用到了github.com/google/gopacket 這個(gè)庫(kù),這個(gè)庫(kù)使用一切正常,但是唯獨(dú)有一個(gè)缺點(diǎn),編譯后的二進(jìn)制文件依賴于libpcap.so的動(dòng)態(tài)庫(kù),這篇文章主要介紹了GO編譯時(shí)避免引入外部動(dòng)態(tài)庫(kù)的解決方法,需要的朋友可以參考下2022-10-10Golang中處理import自定義包出錯(cuò)問(wèn)題的解決辦法
最近開(kāi)始使用Go/GoLand在import自定義包時(shí)出現(xiàn)各種狀況,下面這篇文章主要給大家介紹了關(guān)于Golang中處理import自定義包出錯(cuò)問(wèn)題的解決辦法,文中通過(guò)圖文介紹的非常詳細(xì),需要的朋友可以參考下2023-11-11Golang實(shí)現(xiàn)常見(jiàn)排序算法的示例代碼
現(xiàn)在的面試真的是越來(lái)越卷了,算法已經(jīng)成為了面試過(guò)程中必不可少的一個(gè)環(huán)節(jié),你如果想進(jìn)稍微好一點(diǎn)的公司,算法是必不可少的一個(gè)環(huán)節(jié)。本文為大家準(zhǔn)備了Golang實(shí)現(xiàn)常見(jiàn)排序算法的示例代碼,需要的可以參考一下2022-05-05Gin+Gorm實(shí)現(xiàn)增刪改查的示例代碼
本文介紹了如何使用Gin和Gorm框架實(shí)現(xiàn)一個(gè)簡(jiǎn)單的增刪改查(CRUD)示例,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2024-12-12Golang Map value不可尋址使用指針類型代替示例詳解
這篇文章主要為大家介紹了Golang Map value不可尋址使用指針類型代替示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-11-11GoLand 中設(shè)置默認(rèn)項(xiàng)目文件夾的實(shí)現(xiàn)
本文主要介紹了GoLand 中設(shè)置默認(rèn)項(xiàng)目文件夾的實(shí)現(xiàn),默認(rèn)項(xiàng)目文件夾會(huì)在你打開(kāi)或新建項(xiàng)目時(shí)自動(dòng)預(yù)選,避免每次都需要手動(dòng)導(dǎo)航到目標(biāo)目錄,感興趣的可以了解一下2025-03-03