Go 面試題: new 和 make 是什麼,差別在哪?

如有任何問題或建議,歡迎及時交流和碰撞。個人公衆號是 【腦子進煎魚了】,GitHub 地址: https://github.com/eddycjy

你們好,我是煎魚。git

在 Go 語言中,有兩個比較雷同的內置函數,分別是 newmake 方法,其主要用途都是用於分配相應類型的內存空間。github

看上去 newmake 都是分配內存的,那他們有什麼區別呢?這個細節點也成爲了避免少 Go 語言工程師的面試題之一,值得你們一看。golang

在今天這篇文章中咱們未來解答這個問題。面試

基本特性

make

在 Go 語言中,內置函數 make 僅支持 slicemapchannel 三種數據類型的內存建立,其返回值是所建立類型的自己,而不是新的指針引用數據結構

函數簽名以下:架構

func make(t Type, size ...IntegerType) Type

具體使用示例:函數

func main() {
    v1 := make([]int, 1, 5)
    v2 := make(map[int]bool, 5)
    v3 := make(chan int, 1)
    
    fmt.Println(v1, v2, v3)
}

在代碼中,咱們分別對三種類型調用了 make 函數進行了初始化。你會發現有的入參是有多個長度指定,有的沒有。微服務

這塊的區別主要是長度(len)和容量(cap)的指定,有的類型是沒有容量這一說法,所以天然也就沒法指定。spa

輸出結果:設計

[0] map[] 0xc000044070

有一個細節點要注意,調用 make 函數去初始化切片(slice)的類型時,會帶有零值,須要明確是否須要。

見過很多的小夥伴在這上面踩坑。

new

在 Go 語言中,內置函數 new 能夠對類型進行內存建立和初始化。其返回值是所建立類型的指針引用,與 make 函數在實質細節上存在區別。

函數簽名以下:

func new(Type) *Type

具體使用示例:

type T struct {
    Name string
}

func main() {
    v := new(T)
    v.Name = "煎魚"
}

從上面的例子的效果來看,是否是似曾類似?其實與下面這種方式的同樣的:

func main() {
    v := T{}
    v.Name = "煎魚"
}

輸出結果均是:

&{Name:煎魚}

其實 new 函數在平常工程代碼中是比較少見的,由於他可被替代。

通常會直接用快捷的 T{} 來進行初始化,由於常規的結構體都會帶有結構體的字面屬性:

func NewT() *T {
    return &T{Name: "煎魚"}
}

這種初始化方式更方便。

區別在哪裏

可能會有的小夥伴會疑惑一點,就是 new 函數也能初始化 make 的三種類型:

v1 := new(chan bool)
    v2 := new(map[string]struct{})

make 函數的區別,優點是什麼呢?

本質上在於 make 函數在初始化時,會初始化 slicechanmap 類型的內部數據結構,new 函數並不會。

例如:在 map 類型中,合理的長度(len)和容量(cap)能夠提升效率和減小開銷。

更進一步的區別:

  • make 函數:

    • 可以建立類型所需的內存空間,返回引用類型的自己。
    • 具備使用範圍的侷限性,僅支持 channelmapslice 三種類型。
    • 具備獨特的優點,make 函數會對三種類型的內部數據結構(長度、容量等)賦值。
  • new 函數:

    • 可以建立並分配類型所需的內存空間,返回指針引用(指向內存的指針)。
    • 可被替代,可以經過字面值快速初始化。

總結

在這篇文章中,咱們介紹了 Go 語言中 makenew 函數的使用,並針對其區別點進行了分析。

可能會有小夥伴疑惑,那 newmake 函數所初始化出來的內存,是分配在堆仍是棧上呢?

這就涉及到 Go 語言中的 「逃逸分析」 了(我公衆號前幾天的文章有發),若是所初始化的變量不須要在當前做用域外生存,那麼理論上就不須要初始化在堆上。

個人公衆號

分享 Go 語言、微服務架構和奇怪的系統設計,歡迎你們關注個人公衆號和我進行交流和溝通。

最好的關係是互相成就,各位的點贊就是煎魚創做的最大動力,感謝支持。

相關文章
相關標籤/搜索