Golang 使用 make 還是 new

在 Go 中初始化變量的時候,會用到 make 和 new,如果學習過其他的面嚮對象語言,比如 Java,可能就會對 new 的使用有點迷惑,Go 中的 new 有着完全不同的含義。

make 和 new 都涉及到內存的分配,但使用的場景卻大不相同。

  1. make

make 的使用比較簡單,用來初始化內置的數據結構,slice、map 和 channel,使用 make 返回的都是引用類型。對於不同的結構,返回的結果不同。

make 接收的是可變參數,對於不同的類型,使用的參數不同。

初始化 slice 時,至少需要兩個參數,一個是 slice 的類型,另一個是 slice 的 cap 和 len,如果 len 和 cap 不同,就需要使用三個參數:

s := make([]int, 10)
fmt.Println(len(s)) // 10
fmt.Println(cap(s)) // 10
s := make([]int, 5, 10)
fmt.Println(len(s)) // 5
fmt.Println(cap(s)) // 10

初始化 map 時,只需要一個參數,如果需要預先指定 map 底層存儲的大小,那就需要兩個參數:

m := make(map[string]string, 10)

初始化 channel 時,如果不指定第二個參數,那就會創建一個同步的 channel,否則就會創建一個帶緩衝的 channel:

c := make(chan int, 10)

make 只會用來初始化以上三種數據結構

  1. new

new 的使用就會廣泛很多,new 會爲傳入的類型分配一塊內存,初始化該類型的零值,並返回這個內存的地址

如果想要聲明一個 int 類型的變量,並獲取到該變量的指針:

var i int
p := &i   
fmt.Println(*p) // 0

如果使用 new:

p := new(int)
fmt.Println(*p) // 0

以上的兩種方式是等價的。

除了這些類型,還可以把 new 用在自定的類型上:

type Person struct {
  Name string
  Age  int
}
p := new(Person)
p.Name = "ray"
p.Age  = 18

這裏有一點很特殊的地方,上面說到了使用 make 來初始化三種內置的數據結構,如果使用 new 去創建上面三種類型會發生什麼呢?

m := new(map[string]string)
fmt.Println(*m == nil) // true
s := new([]int)
fmt.Println(*s == nil) // true
c := new(chan int)
fmt.Println(*c == nil) // true

使用 new 創建之後的結構都是 nil,這是因爲 slice、map 和  channel 都是引用類型,而引用類型的零值就是 nil,這個結果是符合上面對於 new 的描述。

通常情況下,不應該使用 new 去創建這三種結構,而是使用 make。

  1. 小結

make 和 new 雖然都用來初始化新變量,但適用的情況卻不一樣,make 主要用來初始化三種內置的引用類型的數據結構,而 new 則更通用一些,主要爲一些值類型的變量申請內存。而且還需要注意一點,make 和 new 都不屬於關鍵,而且內置函數,也就是說,下面的這種代碼是合法的:

func Cal(make, new int) int {
  return make + new
}

在這個函數中,就無法使用 make 或者 new 來初始化變量了。

文 / Rayjun

本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源https://mp.weixin.qq.com/s/c57HU_XiAkT56gSVLU83zg