bl双性强迫侵犯h_国产在线观看人成激情视频_蜜芽188_被诱拐的少孩全彩啪啪漫画

Golang切片Slice底層源碼簡介

這篇文章將為大家詳細講解有關Golang切片Slice底層源碼簡介,小編覺得挺實用的,因此分享給大家做個參考,希望大家閱讀完這篇文章后可以有所收獲。

岳陽樓網站制作公司哪家好,找創新互聯!從網頁設計、網站建設、微信開發、APP開發、響應式網站設計等網站項目制作,到程序開發,運營維護。創新互聯公司2013年成立到現在10年的時間,我們擁有了豐富的建站經驗和運維經驗,來保證我們的工作的順利進行。專注于網站建設就選創新互聯

數組

說切片前先說下數組。數組的兩個特性

  • 一段連續內存地址,每個元素都是連續的

  • 元素的類型相同,并且元素個數固定

Go 數組是值類型,賦值和函數傳參操作都會復制整個數組數據。

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)是對數組一個連續片段的引用,所以切片是一個引用類型.切片是一個長度可變的數組。

Slice 的數據結構定義如下:

runtime/slice.go#L13

type slice struct {
    array unsafe.Pointer    len   int
    cap   int}
  • array 就是底層數組的地址

  • 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)}

基本邏輯就是根據容量申請一塊內存。

切片擴容

擴容是當切片的長度大于容量的時候,底層數組已經裝不下時

func growslice(et *_type, old slice, cap int) slice {
    ...
    // 如果新要擴容的容量比原來的容量還要小,直接報panic
    if cap < old.cap {
        panic(errorString("growslice: cap out of range"))
    }
    // 如果當前切片的大小為0,還調用了擴容方法,那么就新生成一個新的容量的切片返回
    // []struct{}
    if et.size == 0 {
        return slice{unsafe.Pointer(&zerobase), old.len, cap}
    }

    newcap := old.cap
    doublecap := newcap + newcap    //要擴容的容量大于2 *oldcap 新切片容量 = 該容量
    if cap > doublecap {
        newcap = cap
    } else {
    // 舊容量 小于1024,新容量= 舊容量 * 2 也就是擴容1倍
        if old.cap < 1024 {
            newcap = doublecap        } else {
            // 擴容容量 = 舊容量 +舊容量*1/4
            for 0 < newcap && newcap < cap {
                newcap += newcap / 4
            }
            //溢出之后 新容量=要擴容的容量
            if newcap <= 0 {
                newcap = cap
            }
        }
    }

    var overflow bool
    // 計算新的切片的容量,長度。
    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)
        }
    }
    //移動到p
    memmove(p, old.array, lenmem)
    //返回slice結構,讓slice.array指向p
    return slice{p, old.len, newcap}}
  • 新申請容量cap,如果大于2倍舊容量(oldcap),要擴容的容量(newcap)=新申請容量cap

  • 如果舊容量(oldcap)< 1024, 要擴容的容量(newcap)在舊容量(oldcap)基礎上擴容1倍,否則則擴容 1/4

  • 如果數值溢出,要擴容的容量 = 新申請的容量

  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
  • 注意事項: 切片共享底層數組,所以在切片賦值的時候,修改切片會導致底層數組改變,而產生BUG

arr := []int{1,2,3,4}
arr1 := arr[:2] //[1,2]
arr1 = append(arr1,5)
fmt.Println(arr[3]) //5 修改了底層數組
//例子2
arr3 := []int{1,2,3,4}
arr4 := arr3[2:]
arr4 = append(arr4,10)//擴容 不會影響arr3
fmt.Println(arr3)

切片復制

src/runtime/slice.go#L247

//toPtr 目標地址 toLen目標長度
// 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
    //特殊處理 如果只有一個元素并且大小是1byte,那么指針直接轉換即可
    if size == 1 {
        *(*byte)(toPtr) = *(*byte)(fromPtr)
    } else {
        //從 fm.array 地址開始,拷貝到 to.array 地址之后
        memmove(toPtr, fromPtr, size)
    }
    return n
}

關于“Golang切片Slice底層源碼簡介”這篇文章就分享到這里了,希望以上內容可以對大家有一定的幫助,使各位可以學到更多知識,如果覺得文章不錯,請把它分享出去讓更多的人看到。

分享文章:Golang切片Slice底層源碼簡介
本文地址:http://vcdvsql.cn/article32/gdihpc.html

成都網站建設公司_創新互聯,為您提供用戶體驗服務器托管App開發外貿建站建站公司App設計

廣告

聲明:本網站發布的內容(圖片、視頻和文字)以用戶投稿、用戶轉載內容為主,如果涉及侵權請盡快告知,我們將會在第一時間刪除。文章觀點不代表本網站立場,如需處理請聯系客服。電話:028-86922220;郵箱:631063699@qq.com。內容未經允許不得轉載,或轉載時需注明來源: 創新互聯

成都seo排名網站優化