Go make 和 new 的區別

2021-10-09 00:27:29 字數 4303 閱讀 4917

在 go 中對某種型別進行初始化時會用到makenew, 因為它們的功能相似,所以初學者可能對它們的感到困惑;本文將由淺入深的介紹其功能和區別

長話短說,先放上結論:

方法作用

作用物件

返回值new

分配記憶體

值型別和使用者定義的型別

初始化為零值,返回指標

make

分配記憶體

內建引用型別(map, slice, channel)

初始化為零值,返回引用型別本身

以上為makenew的區別,如果有人追問能說的更詳細點嗎?

哦豁,這就很尷尬了

短話長說,我們看看makenew究竟做了什麼

先說要點,new 用來分配記憶體,並初始化零值,返回零值指標

在編譯過程中,使用 new 大致會產生 2 種情況:

若該物件申請的空間為 0,則返回表示空指標的zerobase變數,這類物件比如:slice,map,channel以及一些結構體等。

// path: src/runtime/malloc.go

// base address for all 0-byte allocations

var zerobase uintptr

其他情況則會使用runtime.newobject函式:

// path: src/runtime/malloc.go

func

newobject

(typ *_type) unsafe.pointer

這一塊的內容也比較簡單,runtime.newoject呼叫了runtime.mallocgc函式去開闢一段記憶體空間,然後返回那塊空間的位址

這裡可以做個簡單的例子去驗證一下:

func

main()

說到底new實現什麼功能呢,可以這樣去理解

// a := new(int); 其他型別以此模擬

var a int

return

&a

make是用來初始化map,slice,channel這幾種特定型別的

在編譯過程中,用make去初始化不同的型別會呼叫不同的底層函式:

初始化map, 呼叫runtime.makemap初始化slice, 呼叫runtime.makeslice初始化channel,呼叫runtime.makechan

接下來我們看這些函式的原始碼部分,**它們與new的不同,如果了解這幾種型別的原始碼,很容易理解下面的**;如果不了解這塊內容的同學可以跟著注釋走,了解流程就可以了

runtime.makemap:

// path: src/runtime/map.go

func

makemap

(t *maptype, hint int

, h *hmap)

*hmap

// 生成 hash 種子

h.hash0 =

fastrand()

// 計算 桶 的數量

b :=

uint8(0

)for

overloadfactor

(hint, b)

h.b = b

if h.b !=

0return h

}

這裡為了方便檢視,省去了部分**。我們可以看到這裡的步驟很多,h = new(hmap)只是其中的一部分

runtime.makeslice:

// path: src/runtime/slice.go

func

makeslice

(et *_type,

len,

capint

) unsafe.pointer

// panic: cap 超出範圍

panicmakeslicecap()

}return

mallocgc

(mem, et,

true

)}

這裡其實和new底層的runtime.newobject很相似了,只是這裡多了一些異常處理

runtime.makechan:

// path: src/runtime/chan.go

func

makechan

(t *chantype, size int

)*hchan

// 初始化 hchan 的內部字段

c.elemsize =

uint16

(elem.size)

c.elemtype = elem

c.dataqsiz =

uint

(size)

...}

這裡省略了部分**,包括一些異常處理

總之,make相對於new來說,做的事情更多,new只是開闢了記憶體空間,make為更加複雜的資料結構開闢記憶體空間並對一些字段進行初始化

注意:有心細的同學可以發現,runtime,makemap,runtime,makeslice,runtime.makechan返回的是指標型別,但並不意味著用 make 初始化後,返回的是指標型別,這裡上面列出來的是比較核心部分的原始碼,並不是所有的原始碼

可以用 new 去初始化 map, slice 和 channel 嗎?

首先我們回憶一下new的功能,簡單理解如下:

var i int

return

&int

如果我們要去初始化上面幾種型別要怎麼去做:

m :=

*new

(map

[int

]int

)// 先取值,因為 new 返回的是指標

s :=

*new([

]int

) ch :=

*new

(chan

int)

在上述**中,使用new去初始化這幾個型別,是不會 panic 的

針對上述**的情況,我們可以分類討論:

map, new 沒有對 map 做建立桶等初始操作,所以當我們新增鍵值對的時候回 panic, 查詢 和 刪除不存在的 key 時不會引發 panic, 因為查詢和刪除都要查詢桶和 key的過程,如果沒有對應的桶和key,查詢返回零值,刪除則不作操作

channel,也沒有對 channel 的緩衝區開闢記憶體空間以及更多的內部初始話操作,所建立的 channel 始終是 nil,往裡面傳送或從裡面接收資料都會引發 panic

可以用 make 去初始化其他型別嗎,如 int, string ?

不可以,因為 make 沒有對其他型別提供相應的底層方法

以上,由於能力有限,疏忽和不足之處難以避免,歡迎讀者指正,以便及時修改。

go make 和 new 的區別

new 和 make 都可以用來分配空間,初始化型別,但是它們確有不同。new t 為乙個 t 型別新值分配空間並將此空間初始化為 t 的零值,返回的是新值的位址,也就是 t 型別的指標 t,該指標指向 t 的新分配的零值。p1 new int fmt.printf p1 v n p1 int 0x...

Go make 和 new的區別

在go語言中 make 被用來分配引用型別的記憶體 map,slice,channel new 被用來分配除了引用型別的所有其他型別的記憶體 int,string,array等 本文主要給大家介紹了go語言中函式new與make的使用和區別,關於go語言中new和make是內建的兩個函式,主要用來建...

new和malloc的區別

1 new 是c 中的操作符,malloc是c 中的乙個函式 2 new 不止是分配記憶體,而且會呼叫類的建構函式,同理delete會呼叫類的析構函式,而malloc則只分配記憶體,不會進行初始化類成員的工作,同樣free也不會呼叫析構函式 3 記憶體洩漏對於malloc或者new都可以檢查出來的,...