中文字幕av专区_日韩电影在线播放_精品国产精品久久一区免费式_av在线免费观看网站

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

Go語言中make和new有什么區別

發布時間:2023-02-27 09:14:19 來源:億速云 閱讀:86 作者:iii 欄目:開發技術

這篇文章主要介紹“Go語言中make和new有什么區別”,在日常操作中,相信很多人在Go語言中make和new有什么區別問題上存在疑惑,小編查閱了各式資料,整理出簡單好用的操作方法,希望對大家解答”Go語言中make和new有什么區別”的疑惑有所幫助!接下來,請跟著小編一起來學習吧!

    寫在前面

    雖然 make 和 new  都是能夠用于初始化數據結構,但是它們兩者能夠初始化的結構類型卻有著較大的不同;make 在 Go 語言中只能用于初始化語言中的3種類型:slice、map、chan

    slice := make([]int, 0, 100)
    hash := make(map[int]bool, 10)
    ch := make(chan int, 5)

    這些基本類型都是語言為我們提供的,我們在前面的章節中其實已經介紹過了它們初始化的過程以及原理,但是在這里還是需要提醒各位讀者注意的是,這三者返回了不同類型的數據結構:

    • slice 是一個包含 datacap 和 len 的結構體

    • hash 是一個指向 hmap 結構體的指針

    • ch 是一個指向 hchan 結構體的指針

    而另一個用于初始化數據結構的關鍵字 new 的作用其實就非常簡單了,它只是接收一個類型作為參數然后返回一個指向這個類型的指針:

    i := new(int)
    
    var v int
    i := &v

    上述代碼片段中的兩種不同初始化方法其實是等價的,它們都會創建一個指向 int 零值的指針。

    到了這里我們對 Go 語言中這兩種不同關鍵字的使用也有了一定的了解:make 用于創建切片、哈希表和管道等內置數據結構,new 用于分配并創建一個指向對應類型的指針。

    實現原理

    接下來我們將分別介紹 make 和 new 在初始化不同數據結構時的具體過程,我們會從編譯期間和運行時兩個不同的階段理解這兩個關鍵字的原理,不過由于前面已經詳細地介紹過 make 的實現原理,所以我們會將重點放在 new 上從 Go 語言的源代碼層面分析它的實現。

    make

    在前面的章節中我們其實已經談到過 make 在創建 數組和切片、哈希表 和 Channel 的具體過程,所以在這一小節中,我們也只是會簡單提及 make 相關的數據結構初始化原理。

    在編譯期間的 類型檢查 階段,Go 語言其實就將代表 make 關鍵字的 OMAKE 節點根據參數類型的不同轉換成了 OMAKESLICEOMAKEMAP 和 OMAKECHAN 三種不同類型的節點,這些節點最終也會調用不同的運行時函數來初始化數據結構。

    new

    內置函數 new 會在編譯期間的 SSA 代碼生成 階段經過 callnew 函數的處理,如果請求創建的類型大小時 0,那么就會返回一個表示空指針的 zerobase 變量,在遇到其他情況時會將關鍵字轉換成 newobject

    func callnew(t *types.Type) *Node {
        if t.NotInHeap() {
            yyerror("%v is go:notinheap; heap allocation disallowed", t)
        }
        dowidth(t)
    
        if t.Size() == 0 {
            z := newname(Runtimepkg.Lookup("zerobase"))
            z.SetClass(PEXTERN)
            z.Type = t
            return typecheck(nod(OADDR, z, nil), ctxExpr)
        }
    
        fn := syslook("newobject")
        fn = substArgTypes(fn, t)
        v := mkcall1(fn, types.NewPtr(t), nil, typename(t))
        v.SetNonNil(true)
        return v
    }

    需要提到的是,哪怕當前變量是使用 var 進行初始化,在這一階段可能會被轉換成 newobject 的函數調用并在堆上申請內存:

    func walkstmt(n *Node) *Node {
        switch n.Op {
        case ODCL:
            v := n.Left
            if v.Class() == PAUTOHEAP {
                if prealloc[v] == nil {
                    prealloc[v] = callnew(v.Type)
                }
                nn := nod(OAS, v.Name.Param.Heapaddr, prealloc[v])
                nn.SetColas(true)
                nn = typecheck(nn, ctxStmt)
                return walkstmt(nn)
            }
        case ONEW:
            if n.Esc == EscNone {
                r := temp(n.Type.Elem())
                r = nod(OAS, r, nil)
                r = typecheck(r, ctxStmt)
                init.Append(r)
                r = nod(OADDR, r.Left, nil)
                r = typecheck(r, ctxExpr)
                n = r
            } else {
                n = callnew(n.Type.Elem())
            }
        }
    }

    當然這也不是絕對的,如果當前聲明的變量或者參數不需要在當前作用域外『生存』,那么其實就不會被初始化在堆上,而是會初始化在當前函數的棧中并隨著 函數調用 的結束而被銷毀。

    newobject 函數的工作就是獲取傳入類型的大小并調用 mallocgc 在堆上申請一片大小合適的內存空間并返回指向這片內存空間的指針:

    func newobject(typ *_type) unsafe.Pointer {
        return mallocgc(typ.size, typ, true)
    }

    mallocgc 函數的實現大概有 200 多行代碼,在這一節中就不展開詳細分析了,我們會在后面的章節中詳細介紹 Go 語言的內存管理機制。

    到此,關于“Go語言中make和new有什么區別”的學習就結束了,希望能夠解決大家的疑惑。理論與實踐的搭配能更好的幫助大家學習,快去試試吧!若想繼續學習更多相關知識,請繼續關注億速云網站,小編會繼續努力為大家帶來更多實用的文章!

    向AI問一下細節

    免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

    AI

    莲花县| 昌邑市| 东辽县| 柘荣县| 岱山县| 永宁县| 水富县| 乐安县| 报价| 大足县| 营口市| 昆明市| 江源县| 广汉市| 广平县| 大连市| 襄城县| 兴山县| 云南省| 噶尔县| 沾益县| 武隆县| 河池市| 祁门县| 望都县| 雅江县| 正阳县| 铁岭市| 丽水市| 昌吉市| 潼南县| 北票市| 洛扎县| 余江县| 城步| 临澧县| 靖安县| 韩城市| 泰州市| 六枝特区| 松阳县|