go 中make 和 new 的區別

來源:互聯網
上載者:User

參考教程:
http://www.flysnow.org/2017/03/26/go-in-action-go-type.html
http://www.flysnow.org/2017/10/23/go-new-vs-make.html

1 變數的類型

想弄明白 make 和 new 的區別,首先要分清楚參考型別和實值型別。

1.1 實值型別

golang 中內建未經處理資料類型是實值型別。比如int、float、string、bool。實值型別是不可變的,所以對他們進行操作,一般會返回一個新建立的值。把這些值傳遞給函數時,其實建立的是一個值的副本。這一點在python中也是相同的。作為參數傳遞給函數的都是一個副本。

func main(){  s := "a"  modify(s)  fmt.Println(s)}func modify(s string)string{  s = "888888888"}

因為修改實值型別,產生的都是它的一個副本,所以實值型別在多線程中是安全的。

1.2 參考型別

切片、map、介面、函數類型以及chan都是參考型別。參考型別的修改可以影響到任何引用到它的變數。

參考型別之所以可以引用,是因為我們在建立參考型別的變數,其實是一個標題值,標題值裡包含一個指標,指向底層的資料結構,在函數中傳遞參考型別時,傳遞的是這個標題值的副本,它所指向的底層結構並沒有被複製傳遞,這也是參考型別傳遞高效的原因。

func main(){  ages := map[string]int{"s":12}  modify(ages)  fmt.Println(ages)}func modify(m map[string]int){  m["s"] = 777}

函數 modify 的修改,會影響 ages 的值。

1.3 結構類型

用 var 關鍵字聲明一個結構體類型的變數。

type person struct{  age int  name string}// 聲明var p person

這種 var 聲明的方式,會對結構體 person 裡的資料類型預設初始化,也就是使用它們類型的零值。
函數傳參是值傳遞,所以對於結構體來說也不例外,結構體傳遞的是其本身以及裡面的值的拷貝。

type Person struct {    age int    name string}func modify(p Person){    p.age  = 100000000000}func main(){    jim := Person{10,"jim"}    fmt.Println(jim)    modify(jim)    fmt.Println(jim)}

以上的輸出都是一樣的,所以我們驗證傳遞的是值的副本。如果上面的例子我們要修改 age 的值可以通過傳遞結構體的指標。

type Person struct {    age int    name string}// 我覺得這樣比較好理解,*Person 是針對結構體執行個體的操作。(可以想想物件導向的語言,Python / Java)func modify(p *Person){    p.age  = 100000000000}func main(){// jim 的類型是 Person    jim := Person{10,"jim"}// var jim Person = Person{10, "jim"}    fmt.Println(jim)// &jim 指向的是執行個體    modify(&jim)// var h *Person = &jim    fmt.Println(jim)// * 號在定義時使用,&在運算時使用。*這種類型在運算時映射的值是&}

1.4 自訂類型

type Duration int64

Go是強型別語言,所以 int64 與 Duration不能直接賦值。

2 變數的聲明

var i intvar s string

變數的聲明可以通過 var 關鍵字,然後就可以在程式中使用了,var 聲明的變數的值是他們預設的零值。

類型 預設零值
int 0
string ""
參考型別 nil

對參考型別賦值。
*int,是聲明一個實值型別int的參考型別。
*i,是對實值型別的參考型別進行運算。

func main(){  var i *int  *i = 10  fmt.Println(*i)}

運行時的 paninc : runtime error: invalid memory address or nil pointer dereference
從這個提示中可以看出,對於參考型別的變數,我們不光是聲明它,還要為它分配記憶體空間,否則我們的值放在哪去呢?這就是上面錯誤提示的原因。
對於實值型別的聲明則不需要,是因為已經預設幫我們分配好了,實值型別都有一個預設零值。
要分配記憶體,就引出來今天的new 和 make。

new

func main(){  var i *int  i = new(int)  *i = 10  fmt.Println(*i)}

看下 new 這個內建的函數

// 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.func new(Type) *Type

new 是一個分配記憶體的內建函數。new的參數是一個類型,new的傳回值是一個指標。該指標指向參數的預設零值。

func main(){// 這個u 是什麼類型,*user, 為啥?因為new函數返回的是一個指向參數類型預設零值的指標啊。// 這種方式和上文中 u := user{}, &u 的方式實際上是一樣的。    u := new(user)    u.lock.Lock()    u.name = "sssssssss"    u.lock.Unlock()    fmt.Println(u)}type user struct {    lock sync.Mutex    name string    age int}

這就是 new,它返回的永遠是類型的指標,指向配置類型的記憶體位址。

make

make 也用於記憶體配置,但是和 new 不同,它只用於 chan / map 和 且切片的記憶體建立,而且它返回的類型就是這三個類型本身,而不是它們的指標類型。因為chan / map / 切片已經是參考型別了,所以沒必要返回他們的指標了。
看一下 make 的文檔

The make built-in function allocates and initializes an object of type slice, map, or chan (only).Like new,the 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:

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, so make([]int,0,10) allocates a slice of length 0 and capacity 10.

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.

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

make 只為 slice/ map/ chan 初始化,分配記憶體。
和new 類似,第一個參數必須是一個類型。和 new 不同的是,new 返回的是參數類型的指標,指標指向的該參數的預設零值。而make返回的是傳入類型相同,並不是指標。因為 slice / map / chan 本身就是參考型別了。

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.