<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
當我們想要在 Go 語言中初始化一個結構時,其實會使用到兩個完全不同的關鍵字,也就是 make
和 new
,同時出現兩個用於『初始化』的關鍵字對於初學者來說可能會感到非常困惑,不過它們兩者有著卻完全不同的作用。
在 Go 語言中,make
關鍵字的主要作用是初始化內建的資料結構,也就是我們在前面提到的 陣列和切片、雜湊表 和 Channel,而當我們想要獲取指向某個型別的指標時其實可以使用 new
關鍵字,只是知道如何使用 new
的人真的比較少,我們在這一節中就會介紹 make
和 new
它們的區別以及實現原理。
雖然 make
和 new
都是能夠用於初始化資料結構,但是它們兩者能夠初始化的結構型別卻有著較大的不同;make
在 Go 語言中只能用於初始化語言中的基本型別:
slice := make([]int, 0, 100) hash := make(map[int]bool, 10) ch := make(chan int, 5)
這些基本型別都是語言為我們提供的,我們在前面的章節中其實已經介紹過了它們初始化的過程以及原理,但是在這裡還是需要提醒各位讀者注意的是,這三者返回了不同型別的資料結構:
slice
是一個包含 data
、cap
和 len
的結構體;hash
是一個指向 hmap
結構體的指標;ch
是一個指向 hchan
結構體的指標;而另一個用於初始化資料結構的關鍵字 new
的作用其實就非常簡單了,它只是接收一個型別作為引數然後返回一個指向這個型別的指標:
i := new(int) var v int i := &v
上述程式碼片段中的兩種不同初始化方法其實是等價的,它們都會建立一個指向 int
零值的指標。
到了這裡我們對 Go 語言中這兩種不同關鍵字的使用也有了一定的瞭解:make
用於建立切片、雜湊表和管道等內建資料結構,new
用於分配並建立一個指向對應型別的指標。
接下來我們將分別介紹 make
和 new
在初始化不同資料結構時的具體過程,我們會從編譯期間和執行時兩個不同的階段理解這兩個關鍵字的原理,不過由於前面已經詳細地介紹過 make
的實現原理,所以我們會將重點放在 new
上從 Go 語言的原始碼層面分析它的實現。
在前面的章節中我們其實已經談到過 make
在建立 陣列和切片、雜湊表 和 Channel 的具體過程,所以在這一小節中,我們也只是會簡單提及 make
相關的資料結構初始化原理。
在編譯期間的 型別檢查 階段,Go 語言其實就將代表 make
關鍵字的 OMAKE
節點根據引數型別的不同轉換成了 OMAKESLICE
、OMAKEMAP
和 OMAKECHAN
三種不同型別的節點,這些節點最終也會呼叫不同的執行時函數來初始化資料結構。
內建函數 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
關鍵字的實現原理,make
關鍵字的主要作用是建立切片、雜湊表和 Channel 等內建的資料結構,而 new
的主要作用是為型別申請一片記憶體空間,並返回指向這片記憶體的指標。
到此這篇關於一文告訴你大神是如何學習Go語言之make和new的文章就介紹到這了,更多相關Go語言make new內容請搜尋it145.com以前的文章或繼續瀏覽下面的相關文章希望大家以後多多支援it145.com!
相關文章
<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
综合看Anker超能充系列的性价比很高,并且与不仅和iPhone12/苹果<em>Mac</em>Book很配,而且适合多设备充电需求的日常使用或差旅场景,不管是安卓还是Switch同样也能用得上它,希望这次分享能给准备购入充电器的小伙伴们有所
2021-06-01 09:31:42
除了L4WUDU与吴亦凡已经多次共事,成为了明面上的厂牌成员,吴亦凡还曾带领20XXCLUB全队参加2020年的一场音乐节,这也是20XXCLUB首次全员合照,王嗣尧Turbo、陈彦希Regi、<em>Mac</em> Ova Seas、林渝植等人全部出场。然而让
2021-06-01 09:31:34
目前应用IPFS的机构:1 谷歌<em>浏览器</em>支持IPFS分布式协议 2 万维网 (历史档案博物馆)数据库 3 火狐<em>浏览器</em>支持 IPFS分布式协议 4 EOS 等数字货币数据存储 5 美国国会图书馆,历史资料永久保存在 IPFS 6 加
2021-06-01 09:31:24
开拓者的车机是兼容苹果和<em>安卓</em>,虽然我不怎么用,但确实兼顾了我家人的很多需求:副驾的门板还配有解锁开关,有的时候老婆开车,下车的时候偶尔会忘记解锁,我在副驾驶可以自己开门:第二排设计很好,不仅配置了一个很大的
2021-06-01 09:30:48
不仅是<em>安卓</em>手机,苹果手机的降价力度也是前所未有了,iPhone12也“跳水价”了,发布价是6799元,如今已经跌至5308元,降价幅度超过1400元,最新定价确认了。iPhone12是苹果首款5G手机,同时也是全球首款5nm芯片的智能机,它
2021-06-01 09:30:45