Go 面試題: New 和 Make 是什么,差異在哪?
本文轉(zhuǎn)載自微信公眾號「腦子進(jìn)煎魚了」,作者陳煎魚。轉(zhuǎn)載本文請聯(lián)系腦子進(jìn)煎魚了公眾號。
大家好,我是煎魚。
在 Go 語言中,有兩個比較雷同的內(nèi)置函數(shù),分別是 new 和 make 方法,其主要用途都是用于分配相應(yīng)類型的內(nèi)存空間。
看上去 new 和 make 都是分配內(nèi)存的,那他們有什么區(qū)別呢?這個細(xì)節(jié)點(diǎn)也成為了不少 Go 語言工程師的面試題之一,值得大家一看。
在這篇文章中我們將來解答這個問題。
基本特性
make
在 Go 語言中,內(nèi)置函數(shù) make 僅支持 slice、map、channel 三種數(shù)據(jù)類型的內(nèi)存創(chuàng)建,其返回值是所創(chuàng)建類型的本身,而不是新的指針引用。
函數(shù)簽名如下:
- 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)
- }
在代碼中,我們分別對三種類型調(diào)用了 make 函數(shù)進(jìn)行了初始化。你會發(fā)現(xiàn)有的入?yún)⑹怯卸鄠€長度指定,有的沒有。
這塊的區(qū)別主要是長度(len)和容量(cap)的指定,有的類型是沒有容量這一說法,因此自然也就無法指定。
輸出結(jié)果:
- [0] map[] 0xc000044070
有一個細(xì)節(jié)點(diǎn)要注意,調(diào)用 make 函數(shù)去初始化切片(slice)的類型時,會帶有零值,需要明確是否需要。
見過不少的小伙伴在這上面踩坑。
new
在 Go 語言中,內(nèi)置函數(shù) new 可以對類型進(jìn)行內(nèi)存創(chuàng)建和初始化。其返回值是所創(chuàng)建類型的指針引用,與 make 函數(shù)在實(shí)質(zhì)細(xì)節(jié)上存在區(qū)別。
函數(shù)簽名如下:
- func new(Type) *Type
具體使用示例:
- type T struct {
- Name string
- }
- func main() {
- v := new(T)
- v.Name = "煎魚"
- }
從上面的例子的效果來看,是不是似曾相似?其實(shí)與下面這種方式的一樣的:
- func main() {
- v := T{}
- v.Name = "煎魚"
- }
輸出結(jié)果均是:
- &{Name:煎魚}
其實(shí) new 函數(shù)在日常工程代碼中是比較少見的,因?yàn)樗杀惶娲?/p>
一般會直接用快捷的 T{} 來進(jìn)行初始化,因?yàn)槌R?guī)的結(jié)構(gòu)體都會帶有結(jié)構(gòu)體的字面屬性:
- func NewT() *T {
- return &T{Name: "煎魚"}
- }
這種初始化方式更方便。
區(qū)別在哪里
可能會有的小伙伴會疑惑一點(diǎn),就是 new 函數(shù)也能初始化 make 的三種類型:
- v1 := new(chan bool)
- v2 := new(map[string]struct{})
那 make 函數(shù)的區(qū)別,優(yōu)勢是什么呢?
本質(zhì)上在于 make 函數(shù)在初始化時,會初始化 slice、chan、map 類型的內(nèi)部數(shù)據(jù)結(jié)構(gòu),new 函數(shù)并不會。
例如:在 map 類型中,合理的長度(len)和容量(cap)可以提高效率和減少開銷。
更進(jìn)一步的區(qū)別:
- make 函數(shù):
- 能夠分配并初始化類型所需的內(nèi)存空間和結(jié)構(gòu),返回引用類型的本身。
- 具有使用范圍的局限性,僅支持 channel、map、slice 三種類型。
- 具有獨(dú)特的優(yōu)勢,make 函數(shù)會對三種類型的內(nèi)部數(shù)據(jù)結(jié)構(gòu)(長度、容量等)賦值。
- new 函數(shù):
- 能夠分配類型所需的內(nèi)存空間,返回指針引用(指向內(nèi)存的指針)。
- 可被替代,能夠通過字面值快速初始化。
總結(jié)
在這篇文章中,我們介紹了 Go 語言中 make 和 new 函數(shù)的使用,并針對其區(qū)別點(diǎn)進(jìn)行了分析。
可能會有小伙伴疑惑,那 new 和 make 函數(shù)所初始化出來的內(nèi)存,是分配在堆還是棧上呢?
這就涉及到 Go 語言中的 “逃逸分析” 了(我公眾號前幾天的文章有發(fā)),如果所初始化的變量不需要在當(dāng)前作用域外生存,那么理論上就不需要初始化在堆上。