1. Go語言中的值類型和引用類型
- 值類型:int,float,bool,string,struct和數組 (數組要特別注意,別搞混了)
變量直接存儲值,分配棧區的內存空間,這些變量所占據的空間在函數被調用完后會自動釋放。
- 引用類型:slice,map,chan和值類型對應的指針
變量存儲的是一個地址(或者理解為指針),指針指向內存中真正存儲數據的首地址。內存通常在堆上分配,通過GC回收。
2. new() vs make()
對值類型和引用類型了解之后,再來理解new()和make()就不難了,其實只要有C/C++背景的理解起來都不難。比如我們聲明一個int類型的數據,一般是這樣的:
var i int
var s string
當我們不指定變量的默認值時,這些變量的默認值就是對應的零值。(int類型的零值是0,string類型的零值是"",引用類型的零值是nil)。我們可以直接對值類型的變量進行賦值,修改變量對應的值等等。但是,如果聲明的變量是引用類型呢?這就需要用到new()或make()函數了。先來看這樣一個例子:
var i int // 值類型 i = 10 fmt.Println(i) // 10 var p *int // 引用類型 *p = 10 fmt.Println(*p) //panic: runtime error: invalid memory address or nil pointer dereference
從例子可以看到,當對指針p進行賦值的時候,出現了panic,提示p 是無效的內存地址或是空指針引用。也就是說,對於引用類型的變量,我們不僅要聲明變量(這僅僅是給變量取個名字),更重要的是,我們得手動為它分配空間!好在Go中還有GC,如果是C/C++,對於指針類型,除了手動申請空間,更要手動釋放空間。
new()方法就是為 int/bool/struct等 值類型分配內存空間,返回相應類型的指針;而make()就是專為slice,map,channel分配空間。
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
因此,我們可以稍稍修改上面錯誤的程序.
var p *int // 引用類型,或者寫成 p := new(int) p = new(int) *p = 10 fmt.Println(*p) // 10
make()
make也是用於內存分配,但是和new不同,它只用於slice、map和channel的內存創建,它返回的類型就是類型本身,而不是它們的指針類型。
// 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: // 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. func make(t Type, size ...IntegerType) Type
