Golang make和new的區別及實現原理詳解
導讀 | 在Go語言中,有兩個比較雷同的內建函式,分別是new和make方法,二者都可以用來分配記憶體,那他們有什麼區別呢?下面我們就從底層來分析一下二者的不同。感興趣的小夥伴們可以參考借鑑,希望對大家能有所幫助 |
在Go語言中,有兩個比較雷同的內建函式,分別是new和make方法,二者都可以用來分配記憶體,那他們有什麼區別呢?對於初學者可能會覺得有點迷惑,尤其是在掌握不牢固的時候經常遇到panic,下面我們就從底層來分析一下二者的不同。感興趣的小夥伴們可以參考借鑑,希望對大家能有所幫助。
new可以對型別進行記憶體建立和初始化,其返回值是所建立型別的指標引用,這是與make函式的區別之一。我們透過一個示例程式碼看下:
func main() { var a *int fmt.Println(a) // nil *a = 123 //panic fmt.Println(a) }
透過上面程式碼可以看出,當我們透過var宣告一個變數後列印後輸出nil,當我們給這個變數賦值的時候會報錯:
panic: runtime error: invalid memory address or nil pointer dereference [signal SIGSEGV: segmentation violation code=0x1 addr=0x0 pc=0x10a9043]
綜上可以總結出初始化一個指標變數,其值為nil,nil的值是不能直接賦值的。
既然我們知道了沒有為其分配記憶體,那麼我們使用new分配一個吧。程式碼修改後:
func main() { var a *int a = new(int) fmt.Printf("a type is :%T,a point value is :%v,a value is:%v,a size is: %v\n", a, a, *a, unsafe.Sizeof(a)) //a type is :*int,a point value is :0xc00001a0a0,a value is:0,a size is: 8 *a = 123 fmt.Printf("a type is :%T,a point value is :%v,a value is:%v,a size is: %v\n", a, a, *a, unsafe.Sizeof(a)) //a type is :*int,a point value is :0xc00001a0a0,a value is:123,a size is: 8 }
透過以上示例我們可以看到new其返回一個指向新分配的型別為int的指標,指標值為0xc00001a0a0,這個指標指向的內容的值為零(zero value)。透過new進行記憶體分配就可以對其進行賦值。
new函式的簽名如下:
func new(Type) *Type
Type是指變數的型別,可以看到new會根據變數型別返回一個指向該型別的指標。
底層呼叫的是runtime.newobject申請記憶體空間:
func newobject(typ *_type) unsafe.Pointer { return mallocgc(typ.size, typ, true) }
透過呼叫mallocgc在堆上按照typ.size的大小申請記憶體,因此new只會為結構體申請一塊記憶體空間,不會為結構體中的指標型別申請記憶體空間。
make 函式也是用於記憶體分配的,但是和new不同,僅支援 slice、map、channel 三種資料型別的記憶體建立,其返回值是所建立型別的本身,而不是新的指標引用。
注意:這三種型別都是引用型別,所以沒必要返回他們的指標了,必須得初始化,但是不是設定為零值。
我們透過一個示例看一下:
func test() { var s *[]int fmt.Printf("s: %p %#v \n", &s, s) //s: 0xc00000e028 (*[]int)(nil) s = new([]int) fmt.Printf("s: %p %#v \n", &s, s) //s: 0xc00000e028 &[]int(nil) (*s)[0] = 8 fmt.Printf("s: %p %#v \n", &s, s) //panic: runtime error: index out of range [0] with length 0 }
我們先用new進行初始化,會給引用型別初始化為nil,nil是不能直接賦值的。下面改為make。
func test() { var s = make([]int, 5) fmt.Printf("s: %p %#v \n", &s, s) //s: 0xc00000c060 []int{0, 0, 0, 0, 0} s[0] = 8 fmt.Printf("s: %p %#v \n", &s, s) //s: 0xc00000c060 []int{8, 0, 0, 0, 0} }
透過以上示例輸出我們可以看到,make不僅可以開闢一個記憶體,還能給這個記憶體的型別初始化其零值。同理,對於map、channel也是同樣的效果。
make函式的簽名如下:
func make(t Type, size ...IntegerType) Type
可以看到make返回的是複合型別本身。
make在申請slice記憶體時,底層呼叫的是runtime.makeslice,
func makeslice(et *_type, len, cap int) unsafe.Pointer { mem, overflow := math.MulUintptr(et.size, uintptr(cap)) if overflow || mem > maxAlloc || len < 0 || len > cap { mem, overflow := math.MulUintptr(et.size, uintptr(len)) if overflow || mem > maxAlloc || len < 0 { panicmakeslicelen() } panicmakeslicecap() } return mallocgc(mem, et, true) }
可以看到makeslice申請記憶體底層呼叫的也是mallocgc,首先透過MulUintptr根據容量cap乘以type.siz計算出所需要記憶體大小,然後再分配所需記憶體,make為map和channel申請記憶體底層分別是runtime.makemap_small,runtime.makechan,也是同樣呼叫mallocgc。
- make和new都是golang用來分配記憶體的函式,且在堆上分配記憶體,make 即分配記憶體,也初始化記憶體。new只是將記憶體清零,並沒有初始化記憶體。
- make返回的還是引用型別本身;而new返回的是指向型別的指標。
- make只能用來分配及初始化型別為slice,map,channel的資料;new可以分配任意型別的資料。
到此這篇關於深入理解Golang make和new的區別及實現原理的文章就介紹到這了
原文來自:
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/69955379/viewspace-2937991/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- Golang make和new的區別Golang
- 面試官:Golang 的 new 與make 區別是什麼?面試Golang
- Go 語言 new 和 make 關鍵字的區別Go
- 【學習筆記】make 和 new 關鍵字的區別筆記
- new 和 malloc 的區別 及使用
- JavaScript中的new map()和new set()使用詳細(new map()和new set()的區別)JavaScript
- Go 中 make 與 new 的區別是什麼?Go
- CountDownLatch和CyclicBarrier區別及詳解CountDownLatch
- go語言中make和new有什麼作用以及區別?Go
- Linux中&&和&,|和||用法及區別詳解!Linux
- PHP new self()和new static()的區別PHP
- Golang WaitGroup 底層原理及原始碼詳解GolangAI原始碼
- new&instanceof原理解析及模擬實現
- 關於gcc、make和CMake的區別GC
- 詳解 new/bind/apply/call 的模擬實現APP
- Q-Q圖原理詳解及Python實現Python
- JavaScript中new實現原理JavaScript
- JRE 和 JDK 的區別詳解JDK
- MyBatis中#{}和${}的區別詳解MyBatis
- 詳解布隆過濾器的原理和實現過濾器
- 詳解SSL證書系列(8)瞭解HTTPS及和HTTP的區別HTTP
- Python __new__ 和 __init__ 的區別Python
- Redis叢集的三種方式詳解(附優缺點及原理區別)Redis
- call,apply,bind,new實現原理APP
- 詳解 JS 中 new 呼叫函式原理JS函式
- cookie和session的詳解與區別CookieSession
- js防抖和節流的區別及實現方式JS
- 理解new和實現一個new
- bind、call、apply的區別與實現原理APP
- JS節流和防抖的區分和實現詳解JS
- golang reflect 實現原理Golang
- 令牌桶演算法原理及實現(圖文詳解)演算法
- 詳解Spring Retry實現原理Spring
- 深入理解 Go 中的 new() 和 make() 函式Go函式
- MySQL之儲存引擎InnoDB和MyISAM的區別及底層詳解MySql儲存引擎
- __new()__ 與 __init()__的區別
- Python 中__new__方法詳解及使用Python
- iOS中atomic和nonatomic區別及內部實現iOS