Go語言中的內建函數new和make是兩個用於內存分配的原語(allocation primitives)。對於初學者,這二者的區別也挺容易讓人迷糊的。簡單的說,new只分配內存,make用於slice,map,和channel的初始化。數組
這是一個用來分配內存的內建函數,可是與C++不同的是,它並不初始化內存,只是將其置零。也就是說,new(T)會爲T類型的新項目,分配被置零的存儲,而且返回它的地址,一個類型爲*T的值。在Go的術語中,其返回一個指向新分配的類型爲T的指針,這個指針指向的內容的值爲零(zero value)。注意並非指針爲零。數據結構
Go語言中的對象沒有C++中的構造函數,若是用C來描述,Go中的new大概至關於:函數
T *t = (T*)malloc(sizeof(T)) memset(t, 0, sizeof(T))
其實,上面的描可能也不是很準確,也許用*t=zerovalue更準確。由於對於不一樣的數據類型,零值的意義是徹底不同的。好比,對於bool類型,零值爲false;int的零值爲0;string的零值是空字符串:指針
b := new(bool) fmt.Println(*b) i := new(int) fmt.Println(*i) s := new(string) fmt.Println(*s)
輸出:對象
false 0 ""
注意最後有一個空字符串。blog
不少時候,零值並非一個好主意,咱們須要作一些初始化。考慮以下結構體:內存
type Rect struct { x, y float64 width, height float64 }
零值的Rect並無多大用處,咱們如下方式進行初始化:字符串
rect3 := &Rect{0, 0, 100, 200} rect4 := &Rect{width: 100, height: 200}
申明一下,Go語言中沒有C++中的構造函數,對象的建立通常交給一個全局的建立函數來完成:string
func NewRect(x, y, width, height float64) *Rect { return &Rect{x, y, width, height} }
內建函數make(T, args)與new(T)的用途不同。它只用來建立slice,map和channel,而且返回一個初始化的(而不是置零),類型爲T的值(而不是*T)。之因此有所不一樣,是由於這三個類型的背後引用了使用前必須初始化的數據結構。例如,slice是一個三元描述符,包含一個指向數據(在數組中)的指針,長度,以及容量,在這些項被初始化以前,slice都是nil的。對於slice,map和channel,make初始化這些內部數據結構,並準備好可用的值。it
例如:
make([]int, 10, 100)
分配一個有100個int的數組,而後建立一個長度爲10,容量爲100的slice結構,該slice引用包含前10個元素的數組。對應的,new([]int)返回一個指向新分配的,被置零的slice結構體的指針,即指向值爲nil的slice的指針。
var p *[]int = new([]int) // allocates slice structure; *p == nil; rarely useful var v []int = make([]int, 100) // the slice v now refers to a new array of 100 ints // Unnecessarily complex:這種作法實在是很蛋疼 var p *[]int = new([]int) *p = make([]int, 100, 100) // Idiomatic:習慣的作法 v := make([]int, 100)
記住make只用於map,slice和channel,而且不返回指針。要得到一個顯式的指針,使用new進行分配,或者顯式地使用一個變量的地址。
主要參考《effective go》