久久久久久久视色,久久电影免费精品,中文亚洲欧美乱码在线观看,在线免费播放AV片

<center id="vfaef"><input id="vfaef"><table id="vfaef"></table></input></center>

    <p id="vfaef"><kbd id="vfaef"></kbd></p>

    
    
    <pre id="vfaef"><u id="vfaef"></u></pre>

      <thead id="vfaef"><input id="vfaef"></input></thead>

    1. 站長(zhǎng)資訊網(wǎng)
      最全最豐富的資訊網(wǎng)站

      閱讀Golang 切片(Slice)底層源碼

      下面由go語言教程欄目給大家介紹Golang 切片(Slice)底層源碼,希望對(duì)需要的朋友有所幫助!

      閱讀Golang 切片(Slice)底層源碼

      數(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è)長(zhǎng)度可變的數(shù)組。

      Slice 的數(shù)據(jù)結(jié)構(gòu)定義如下:

      runtime/slice.go#L13

      type slice struct {     array unsafe.Pointer    len   int     cap   int}
      • array 就是底層數(shù)組的地址
      • len 切片的長(zhǎng)度
      • cap 切片的容量

      創(chuàng)建切片

      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ò)容

      擴(kuò)容是當(dāng)切片的長(zhǎ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ì)算新的切片的容量,長(zhǎng)度。     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)

      切片復(fù)制

      src/runtime/slice.go#L247

      //toPtr 目標(biāo)地址 toLen目標(biāo)長(zhǎng)度 // width 元素大小 func slicecopy(toPtr unsafe.Pointer, toLen int, fromPtr unsafe.Pointer, fromLen int, width uintptr) int {     //判斷長(zhǎng)度     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 }

      贊(0)
      分享到: 更多 (0)
      網(wǎng)站地圖   滬ICP備18035694號(hào)-2    滬公網(wǎng)安備31011702889846號(hào)