深入學習golang中new與make區別


Go語言中的內建函數new和make是兩個用於內存分配的原語(allocation primitives)。對於初學者,這兩者的區別也挺容易讓人迷糊的。簡單的說,new只分配內存,make用於slice,map,和channel的初始化。

1. new

這是一個用來分配內存的內建函數,但是與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
""

  

  

注意最后有一個空字符串。

2. 初始化

很多時候,零值並不是一個好主意,我們需要做一些初始化。考慮如下結構體:

type Rect struct {

x, y float64

width, height float64

}

零值的Rect並沒有多大用處,我們以下方式進行初始化:

rect3 := &Rect{0, 0, 100, 200}

rect4 := &Rect{width: 100, height: 200}

申明一下,Go語言中沒有C++中的構造函數,對象的創建一般交給一個全局的創建函數來完成:

func NewRect(x, y, width, height float64) *Rect {

return &Rect{x, y, width, height}

}

 

3. make

內建函數make(T, args)與new(T)的用途不一樣。它只用來創建slice,map和channel,並且返回一個初始化的(而不是置零),類型為T的值(而不是*T)。之所以有所不同,是因為這三個類型的背后引用了使用前必須初始化的數據結構。例如,slice是一個三元描述符,包含一個指向數據(在數組中)的指針,長度,以及容量,在這些項被初始化之前,slice都是nil的。對於slice,map和channel,make初始化這些內部數據結構,並准備好可用的值。

例如:

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》

 

 

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM