深入理解 golang 切片機(jī)制(理)

原文

  • 切片總是要有一個(gè)交代的,來(lái)看看這段代碼code
package main

import (
    "fmt"
    "unsafe"
)

type Slice struct {
    ptr unsafe.Pointer // Array pointer
    len int            // slice length
    cap int            // slice capacity
}

// 因?yàn)樾枰羔樣?jì)算,所以需要獲取int的長(zhǎng)度
// 32位 int length = 4
// 64位 int length = 8
var intLen = int(unsafe.Sizeof(int(0)))

func main() {
    s := make([]int, 10, 20)

    // 利用指針讀取 slice memory 的數(shù)據(jù)
    if intLen == 4 { // 32位
        m := *(*[4 + 4*2]byte)(unsafe.Pointer(&s))
        fmt.Println("slice memory:", m)
    } else { // 64 位
        m := *(*[8 + 8*2]byte)(unsafe.Pointer(&s))
        fmt.Println("slice memory:", m)
    }

    // 把slice轉(zhuǎn)換成自定義的 Slice struct
    slice := (*Slice)(unsafe.Pointer(&s))
    fmt.Println("slice struct:", slice)
    fmt.Printf("ptr:%v len:%v cap:%v \n", slice.ptr, slice.len, slice.cap)
    fmt.Printf("golang slice len:%v cap:%v \n", len(s), cap(s))

    s[0] = 0
    s[1] = 1
    s[2] = 2

    // 轉(zhuǎn)成數(shù)組輸出
    arr := *(*[3]int)(unsafe.Pointer(slice.ptr))
    fmt.Println("array values:", arr)

    // 修改 slice 的 len
    slice.len = 15
    fmt.Println("Slice len: ", slice.len)  
    fmt.Println("golang slice len: ", len(s))  
}
  • 看出什么來(lái)了么?
    • 儲(chǔ)備知識(shí):
      • unsafe.Pointer 類似于c語(yǔ)言中的void*
      • unsafe.Pointer所占空間 = int 類型所占字節(jié)數(shù)
    • 結(jié)論:
      • slice的結(jié)構(gòu)等同于Slice結(jié)構(gòu)體
// 每次cap改變,指向array的ptr就會(huì)變化一次
s := make([]int, 1)

fmt.Printf("len:%d cap: %d array ptr: %v \n", len(s), cap(s), *(*unsafe.Pointer)(unsafe.Pointer(&s)))

for i := 0; i < 5; i++ {
    s = append(s, i)
    fmt.Printf("len:%d cap: %d array ptr: %v \n", len(s), cap(s), *(*unsafe.Pointer)(unsafe.Pointer(&s)))
}

fmt.Println("Array:", s)
  • 替換上面的主程序,你發(fā)現(xiàn)了什么呢?
    • 每次append,地址都會(huì)發(fā)生變化 ,說(shuō)明當(dāng)cap不夠的時(shí)候,會(huì)產(chǎn)生復(fù)制操作。
    • 實(shí)際go在append的時(shí)候放大cap是有規(guī)律的。在 cap 小于1024的情況下是每次擴(kuò)大到 2 * cap ,當(dāng)大于1024之后就每次擴(kuò)大到 1.25 * cap 。所以上面的測(cè)試中cap變化是 1, 2, 4, 8
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容