2018-05-05 Go 語言中 make 和 new 的區(qū)別


背景介紹

學(xué)習(xí)Go的時候医咨,遇到了 makenew 的區(qū)別問題芥喇。網(wǎng)上查看了很多文檔靴迫,大體都是4個區(qū)別(見下文),但是缺少更詳細(xì)的說明和更豐富的代碼樣例。比如:

  • zero value of the type(零值)
  • 聲明(declare)霜第、分配內(nèi)存空間(allocate)、初始化(initialize)户辞、賦值泌类,各自的作用
  • 用 new 去給slice、map底燎、chan進(jìn)行內(nèi)存分配刃榨,會是什么結(jié)果?

下面將先介紹官方文檔makenew的定義双仍,然后講解它們的不同點(diǎn)枢希,最后

Talk is cheap. Show me the code.

make

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

The make built-in function allocates and initializes an object of type slice, map, or chan (only). Like new, the first argument is a type, not a value. Unlike new, make's return type is the same as the type of its argument, not a pointer to it. The specification of the result depends on the type:

make() 方法只給類型slice、map朱沃、chan分配內(nèi)存空間苞轿,并初始化一個對象。它的第一個參數(shù)是一個類型逗物,第二個參數(shù)是一個可變長參數(shù)搬卒,返回的是這個類型本身。

Slice: The size specifies the length. The capacity of the slice is
equal to its length. A second integer argument may be provided to
specify a different capacity; it must be no smaller than the
length. For example, make([]int, 0, 10) allocates an underlying array
of size 10 and returns a slice of length 0 and capacity 10 that is
backed by this underlying array.
Map: An empty map is allocated with enough space to hold the
specified number of elements. The size may be omitted, in which case a small starting size is allocated.
Channel: The channel's buffer is initialized with the specified
buffer capacity. If zero, or the size is omitted, the channel is unbuffered.

  1. 對于 slice(切片) 類型翎卓,第一個 size 表示的是切片的長度契邀,第二個 size 表示的是切片的容量。如果只給了一個size參數(shù)失暴,則切片的容量等于其長度坯门;
  2. 對于 map(字典)類型,只有一個size锐帜,表示給map分配一個多大的空間田盈,如果忽略這個參數(shù),則自動分配一個小空間(一般不需要這個參數(shù)缴阎,因?yàn)闀ap會自動擴(kuò)展)允瞧;
  3. 對于 chan(管道)類型,只有一個size蛮拔,表示管道的緩沖區(qū)述暂,無參數(shù)就是無緩沖區(qū)。

new

func new(Type) *Type

The new built-in function allocates memory. The first argument is a type, not a value, and the value returned is a pointer to a newly allocated zero value of that type.
new() 方法分配內(nèi)存空間建炫。它的第一個參數(shù)是一個類型畦韭,然后返回指向該類型的一個內(nèi)存空間的指針。

make vs. new

make new
1 只用于slice肛跌、map艺配、chan 任意結(jié)構(gòu)察郁,包括slice、map转唉、chan
2 傳入的參數(shù)包括一個類型皮钠,還有一個size 只接收一個類型參數(shù),沒有size
3 返回的是類型本身 返回的是類型的指針
4 分配內(nèi)存空間赠法,進(jìn)行初始化 分配內(nèi)存空間麦轰,不進(jìn)行初始化

代碼樣例

上面總結(jié)了makenew的一些不同點(diǎn),下面將針對這些不同點(diǎn)砖织,以及最上面提到的一些問題款侵,進(jìn)行代碼實(shí)驗(yàn)。

zero value of the type(零值)

零值是指創(chuàng)建一個變量后(也就是分配了內(nèi)存空間之后)侧纯,并沒有給該變量一個初始值新锈,那么Go會自動用零值對該變量進(jìn)行初始化。

Type 零值
int, int32, int64 0
float32, float64 0.0
string ""
bool false
pointer, function, interface, slice, channel, map nil
數(shù)組, struct 遞歸初始化為零值

注意:數(shù)組的零值是遞歸初始化數(shù)組元素類型的零值眶熬,而切片的零值是nil

Go的零值在這篇文章中被吐槽了壕鹉。

type TT struct {
    A string
    B int64
    C struct {
        Cd string
        Ce string
        Cf []float64
    }
    G bool
    H float32
}

func main() {
    var i *[]int
    i = new([]int)
    fmt.Println(i, len(*i), cap(*i))                   // &[] 0 0

    var istring *[]string
    istring = new([]string)
    fmt.Println(istring, len(*istring), cap(*istring)) // &[] 0 0

    var tt = new(TT)
    fmt.Println(tt)                        // &{ 0 {  []} false 0}
}

declare、allocate聋涨、initialize、賦值

// 1. 聲明 declare
var i *int
var tt *TT

// 2. 分配內(nèi)存 allocate
i = new(int)
tt = new(TT)

// 聲明 + 分配內(nèi)存
var i = new(int)
var i *int = new(int)
i := new(int)
var tt = new(TT)
var tt *TT = new(TT)
tt := new(TT)
tt := &TT{}

// 3. 初始化 initialize
// 初始化就是第一次賦值
var arr = make([]int, 3) // arr => [0, 0, 0]

// 4. 賦值
i = 4
tt = TT{A: "a", B: 12, ...}

// 聲明 + 賦值
i := TT{A: "a", B: 12, ...}

用new去給 slice负乡、map牍白、chan進(jìn)行內(nèi)存分配

用new對map、chan進(jìn)行內(nèi)存分配抖棘,效果和make差不多茂腥。
但是對slice進(jìn)行內(nèi)存分配時:

    var i *[]int
    i = new([]int)
    fmt.Println(i, len(*i), cap(*i)) // &[] 0 0

    j := make([]int, 3)
    fmt.Println(j, len(j), cap(j))   // [0 0 0] 3 3

本來 slice的零值是 nil,但是 make 會做一次初始化切省,就變成了 [0 0 0]了最岗。
而且 make 的第二個參數(shù)是不可以省略的,但是可以設(shè)置為0朝捆,這樣的話:

    j := make([]int, 0)
    fmt.Println(j, len(j), cap(j))   // [] 0 0

總結(jié)

  1. make只用于 slice般渡、map、channel 的內(nèi)存分配芙盘,new 用于各種類型驯用;
  2. new 返回指針
  3. makenew 多一些參數(shù)

相對而言,make 的功能和使用場景都是很明確的儒老,而 new 的話:

  1. 如果是基礎(chǔ)類型蝴乔,如int,string,不需要使用 new
  2. 如果是基礎(chǔ)類型的指針,在使用該指針(打印花枫,賦值等)前蚌铜,必須先分配內(nèi)存空間睛蛛,就可以用到 new 了捉捅。但是如果直接給從一個變量那里取地址賦值給它厅目,就又不需要 new 了凭迹。
var pInt *int
pInt = new(int)
等價于
var i int = 10
var pInt *int = &i
fmt.Println(*pInt) // 10
  1. 如果是數(shù)組曙聂、切片晦炊、結(jié)構(gòu)體、map類型的指針宁脊,也是類似:
var s *[3]int
s = new([3]int)
等價于
var s *[3]int = &[3]int{}

var s *[]int
s = new([]int)
等價于
var s *[]int = &[]int{}

var t *TT
t = new(TT)
等價于
var t *TT = new(TT)
等價于
var t *TT = &TT{}

var mp = new(map[string]string)
等價于
mp := map[string]string{}

注:chan 不能這么玩(也可能是我沒找對姿勢)

那么問題來了断国,為啥要有 new 呢?
如果有了解的朋友榆苞,希望能指點(diǎn)一下稳衬,多謝!

PS. 有一個思路是坐漏,多看看源碼薄疚,看看哪里用到了new,以及是怎么使用new的赊琳,或許能對new有更深入的了解街夭。

參考文檔

  1. http://docs.studygolang.com/doc/effective_go.html#allocation_new
  2. http://docs.studygolang.com/doc/effective_go.html#allocation_make
  3. http://docs.studygolang.com/doc/faq#new_and_make
  4. https://studygolang.com/articles/3496
  5. http://www.jb51.net/article/126703.htm
  6. https://github.com/astaxie/build-web-application-with-golang/blob/master/zh/02.2.md
    (這個文檔也對 make 和 new 進(jìn)行了對比,也解釋了零值)
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末躏筏,一起剝皮案震驚了整個濱河市板丽,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌趁尼,老刑警劉巖埃碱,帶你破解...
    沈念sama閱讀 216,651評論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異酥泞,居然都是意外死亡砚殿,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,468評論 3 392
  • 文/潘曉璐 我一進(jìn)店門芝囤,熙熙樓的掌柜王于貴愁眉苦臉地迎上來似炎,“玉大人,你說我怎么就攤上這事悯姊∶常” “怎么了?”我有些...
    開封第一講書人閱讀 162,931評論 0 353
  • 文/不壞的土叔 我叫張陵挠轴,是天一觀的道長传睹。 經(jīng)常有香客問我,道長岸晦,這世上最難降的妖魔是什么欧啤? 我笑而不...
    開封第一講書人閱讀 58,218評論 1 292
  • 正文 為了忘掉前任睛藻,我火速辦了婚禮,結(jié)果婚禮上邢隧,老公的妹妹穿的比我還像新娘店印。我一直安慰自己,他們只是感情好倒慧,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,234評論 6 388
  • 文/花漫 我一把揭開白布按摘。 她就那樣靜靜地躺著,像睡著了一般纫谅。 火紅的嫁衣襯著肌膚如雪炫贤。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,198評論 1 299
  • 那天付秕,我揣著相機(jī)與錄音兰珍,去河邊找鬼。 笑死询吴,一個胖子當(dāng)著我的面吹牛掠河,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播猛计,決...
    沈念sama閱讀 40,084評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼唠摹,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了奉瘤?” 一聲冷哼從身側(cè)響起跃闹,我...
    開封第一講書人閱讀 38,926評論 0 274
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎毛好,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體苛秕,經(jīng)...
    沈念sama閱讀 45,341評論 1 311
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡肌访,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,563評論 2 333
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了艇劫。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片吼驶。...
    茶點(diǎn)故事閱讀 39,731評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖店煞,靈堂內(nèi)的尸體忽然破棺而出蟹演,到底是詐尸還是另有隱情,我是刑警寧澤顷蟀,帶...
    沈念sama閱讀 35,430評論 5 343
  • 正文 年R本政府宣布酒请,位于F島的核電站,受9級特大地震影響鸣个,放射性物質(zhì)發(fā)生泄漏羞反。R本人自食惡果不足惜布朦,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,036評論 3 326
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望昼窗。 院中可真熱鬧是趴,春花似錦、人聲如沸澄惊。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,676評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽掸驱。三九已至肛搬,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間亭敢,已是汗流浹背滚婉。 一陣腳步聲響...
    開封第一講書人閱讀 32,829評論 1 269
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留帅刀,地道東北人让腹。 一個月前我還...
    沈念sama閱讀 47,743評論 2 368
  • 正文 我出身青樓,卻偏偏與公主長得像扣溺,于是被迫代替她去往敵國和親骇窍。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,629評論 2 354

推薦閱讀更多精彩內(nèi)容

  • rljs by sennchi Timeline of History Part One The Cognitiv...
    sennchi閱讀 7,322評論 0 10
  • Spring的模型-視圖-控制器(MVC)框架是圍繞一個DispatcherServlet來設(shè)計(jì)的锥余,這個Servl...
    alexpdh閱讀 2,644評論 0 3
  • 什么是土壤板結(jié)驱犹? 土壤板結(jié)是指土壤表層因缺乏有機(jī)質(zhì)嘲恍,結(jié)構(gòu)不良,在灌水或降雨等外因作用下結(jié)構(gòu)破壞雄驹、土料分散,而干燥后...
    七星代閱讀 744評論 1 2
  • 2018.3.24日佃牛,晴,今天是星期六林潤澤做到了星期五說的医舆,睡了個懶覺俘侠,八點(diǎn)半起的床,洗臉?biāo)⒀乐笫呓艺f媽媽我...
    林潤澤閱讀 155評論 0 1