這篇文章將為大家詳細(xì)講解有關(guān)Golang切片Slice底層源碼簡介,小編覺得挺實(shí)用的,因此分享給大家做個(gè)參考,希望大家閱讀完這篇文章后可以有所收獲。
岳陽樓網(wǎng)站制作公司哪家好,找創(chuàng)新互聯(lián)!從網(wǎng)頁設(shè)計(jì)、網(wǎng)站建設(shè)、微信開發(fā)、APP開發(fā)、響應(yīng)式網(wǎng)站設(shè)計(jì)等網(wǎng)站項(xiàng)目制作,到程序開發(fā),運(yùn)營維護(hù)。創(chuàng)新互聯(lián)公司2013年成立到現(xiàn)在10年的時(shí)間,我們擁有了豐富的建站經(jīng)驗(yàn)和運(yùn)維經(jīng)驗(yàn),來保證我們的工作的順利進(jìn)行。專注于網(wǎng)站建設(shè)就選創(chuàng)新互聯(lián)。
數(shù)組
說切片前先說下數(shù)組。數(shù)組的兩個(gè)特性
一段連續(xù)內(nèi)存地址,每個(gè)元素都是連續(xù)的
元素的類型相同,并且元素個(gè)數(shù)固定
Go 數(shù)組是值類型,賦值和函數(shù)傳參操作都會(huì)復(fù)制整個(gè)數(shù)組數(shù)據(jù)。
arr := [2]int{1,2}arr2 := arr fmt.Printf("%p %p",&arr ,&arr2)//切片slice1 := []int{1,2}slice2 := slice1 fmt.Printf("%p %p",slice1 ,slice2)
切片(slice)是對(duì)數(shù)組一個(gè)連續(xù)片段的引用,所以切片是一個(gè)引用類型.切片是一個(gè)長度可變的數(shù)組。
Slice 的數(shù)據(jù)結(jié)構(gòu)定義如下:
runtime/slice.go#L13
type slice struct { array unsafe.Pointer len int cap int}
array 就是底層數(shù)組的地址
len 切片的長度
cap 切片的容量
src/runtime/slice.go#L83
func makeslice(et *_type, len, cap int) unsafe.Pointer { mem, overflow := math.MulUintptr(et.size, uintptr(cap)) .... return mallocgc(mem, et, true)}
基本邏輯就是根據(jù)容量申請(qǐng)一塊內(nèi)存。
擴(kuò)容是當(dāng)切片的長度大于容量的時(shí)候,底層數(shù)組已經(jīng)裝不下時(shí)
func growslice(et *_type, old slice, cap int) slice { ... // 如果新要擴(kuò)容的容量比原來的容量還要小,直接報(bào)panic if cap < old.cap { panic(errorString("growslice: cap out of range")) } // 如果當(dāng)前切片的大小為0,還調(diào)用了擴(kuò)容方法,那么就新生成一個(gè)新的容量的切片返回 // []struct{} if et.size == 0 { return slice{unsafe.Pointer(&zerobase), old.len, cap} } newcap := old.cap doublecap := newcap + newcap //要擴(kuò)容的容量大于2 *oldcap 新切片容量 = 該容量 if cap > doublecap { newcap = cap } else { // 舊容量 小于1024,新容量= 舊容量 * 2 也就是擴(kuò)容1倍 if old.cap < 1024 { newcap = doublecap } else { // 擴(kuò)容容量 = 舊容量 +舊容量*1/4 for 0 < newcap && newcap < cap { newcap += newcap / 4 } //溢出之后 新容量=要擴(kuò)容的容量 if newcap <= 0 { newcap = cap } } } var overflow bool // 計(jì)算新的切片的容量,長度。 var lenmem, newlenmem, capmem uintptr .... var p unsafe.Pointer if et.ptrdata == 0 { p = mallocgc(capmem, nil, false) memclrNoHeapPointers(add(p, newlenmem), capmem-newlenmem) } else { p = mallocgc(capmem, et, true) if lenmem > 0 && writeBarrier.enabled { bulkBarrierPreWriteSrcOnly(uintptr(p), uintptr(old.array), lenmem-et.size+et.ptrdata) } } //移動(dòng)到p memmove(p, old.array, lenmem) //返回slice結(jié)構(gòu),讓slice.array指向p return slice{p, old.len, newcap}}
新申請(qǐng)容量cap,如果大于2倍舊容量(oldcap),要擴(kuò)容的容量(newcap)=新申請(qǐng)容量cap
如果舊容量(oldcap)< 1024, 要擴(kuò)容的容量(newcap)在舊容量(oldcap)基礎(chǔ)上擴(kuò)容1倍,否則則擴(kuò)容 1/4
如果數(shù)值溢出,要擴(kuò)容的容量 = 新申請(qǐng)的容量
arr := make([]int,1024) arr = append(arr,1) fmt.Println(len(arr),cap(arr))// 1025,1280 arr1 := make([]int,10) arr1 = append(arr1,1) fmt.Println(len(arr1),cap(arr1))//11 20
注意事項(xiàng): 切片共享底層數(shù)組,所以在切片賦值的時(shí)候,修改切片會(huì)導(dǎo)致底層數(shù)組改變,而產(chǎn)生BUG
arr := []int{1,2,3,4} arr1 := arr[:2] //[1,2] arr1 = append(arr1,5) fmt.Println(arr[3]) //5 修改了底層數(shù)組 //例子2 arr3 := []int{1,2,3,4} arr4 := arr3[2:] arr4 = append(arr4,10)//擴(kuò)容 不會(huì)影響arr3 fmt.Println(arr3)
src/runtime/slice.go#L247
//toPtr 目標(biāo)地址 toLen目標(biāo)長度 // width 元素大小 func slicecopy(toPtr unsafe.Pointer, toLen int, fromPtr unsafe.Pointer, fromLen int, width uintptr) int { //判斷長度 if fromLen == 0 || toLen == 0 { return 0 } n := fromLen if toLen < n { n = toLen } //切片大小等于0 if width == 0 { return n } size := uintptr(n) * width //特殊處理 如果只有一個(gè)元素并且大小是1byte,那么指針直接轉(zhuǎn)換即可 if size == 1 { *(*byte)(toPtr) = *(*byte)(fromPtr) } else { //從 fm.array 地址開始,拷貝到 to.array 地址之后 memmove(toPtr, fromPtr, size) } return n }
關(guān)于“Golang切片Slice底層源碼簡介”這篇文章就分享到這里了,希望以上內(nèi)容可以對(duì)大家有一定的幫助,使各位可以學(xué)到更多知識(shí),如果覺得文章不錯(cuò),請(qǐng)把它分享出去讓更多的人看到。
分享文章:Golang切片Slice底層源碼簡介
本文地址:http://www.rwnh.cn/article32/gdihpc.html
成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供用戶體驗(yàn)、服務(wù)器托管、App開發(fā)、外貿(mào)建站、建站公司、App設(shè)計(jì)
聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請(qǐng)盡快告知,我們將會(huì)在第一時(shí)間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場,如需處理請(qǐng)聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來源: 創(chuàng)新互聯(lián)