Go中的new()和make()函數(shù)區(qū)別及底層原理詳解
引言
在 Go 語言中,new() 和 make() 是兩個(gè)常用的函數(shù),用于創(chuàng)建和初始化不同類型的變量。本文將深入探討 new() 和 make() 的區(qū)別、使用場景以及底層實(shí)現(xiàn)原理。
- Go 中的
new()和make()函數(shù)是用于創(chuàng)建和初始化變量的重要工具。 new()用于創(chuàng)建指定類型的零值變量,并返回該變量的指針。make()用于創(chuàng)建并初始化引用類型的變量,如切片、映射和通道。
new() 函數(shù)
new()函數(shù)的基本語法及用法。new()創(chuàng)建的變量是指定類型的零值,并返回該變量的指針。new()適用于創(chuàng)建引用類型以外的其他類型變量。
package main
import "fmt"
func main() {
// 使用 new() 創(chuàng)建一個(gè) int 類型的零值變量的指針
numPtr := new(int)
fmt.Println(*numPtr) // 輸出 0
}make() 函數(shù)
make()函數(shù)的基本語法及用法。make()用于創(chuàng)建并初始化引用類型的變量。make()適用于創(chuàng)建切片、映射和通道等引用類型的變量。make()創(chuàng)建的變量不是零值,而是根據(jù)類型進(jìn)行初始化。
package main
import "fmt"
func main() {
// 使用 make() 創(chuàng)建一個(gè)切片,并初始化長度為 3 的切片
slice := make([]int, 3)
fmt.Println(slice) // 輸出 [0 0 0]
}new() 和 make() 的區(qū)別
new()用于創(chuàng)建任意類型的變量,而make()僅用于創(chuàng)建引用類型的變量。new()返回的是指針,而make()返回的是初始化后的值。new()創(chuàng)建的變量是零值,make()創(chuàng)建的變量是根據(jù)類型進(jìn)行初始化。
package main
import "fmt"
func main() {
// 使用 new() 創(chuàng)建一個(gè)結(jié)構(gòu)體的指針
personPtr := new(Person)
personPtr.Name = "Alice"
personPtr.Age = 30
fmt.Println(personPtr) // 輸出 &{Alice 30}
// 使用 make() 創(chuàng)建一個(gè)映射,并初始化鍵值對
m := make(map[string]int)
m["one"] = 1
m["two"] = 2
fmt.Println(m) // 輸出 map[one:1 two:2]
}
type Person struct {
Name string
Age int
}new() 和 make() 的底層實(shí)現(xiàn)原理
在 Go 語言中,new() 和 make() 的底層實(shí)現(xiàn)原理略有不同。
new() 的底層實(shí)現(xiàn)原理
new()函數(shù)在底層使用了 Go 的runtime.newobject函數(shù)。runtime.newobject函數(shù)會分配一塊內(nèi)存,大小為指定類型的大小,并將該內(nèi)存清零。- 然后,
runtime.newobject函數(shù)會返回這塊內(nèi)存的指針。
下面是 new() 函數(shù)的簡化版本的底層實(shí)現(xiàn)原理示例代碼:
package main
import (
"fmt"
"unsafe"
)
func main() {
// 使用 new() 創(chuàng)建一個(gè) int 類型的零值變量的指針
numPtr := new(int)
// 獲得指針的值
ptrValue := uintptr(unsafe.Pointer(numPtr))
// 輸出指針的值
fmt.Println(ptrValue)
}在上述示例代碼中,我們使用了 unsafe 包中的 Pointer 和 uintptr 類型來操作指針。我們首先使用 new(int) 創(chuàng)建一個(gè) int 類型的零值變量的指針 numPtr,然后通過 unsafe.Pointer 將指針轉(zhuǎn)換為 unsafe.Pointer 類型,再通過 uintptr 將 unsafe.Pointer 值轉(zhuǎn)換為 uintptr 類型,最后輸出指針的值。這個(gè)值就是我們所創(chuàng)建的變量的內(nèi)存地址。
make() 的底層實(shí)現(xiàn)原理
make()函數(shù)在底層使用了 Go 的runtime.makeslice、runtime.makemap和runtime.makechan函數(shù)。runtime.makeslice函數(shù)用于創(chuàng)建切片,它會分配一塊連續(xù)的內(nèi)存空間,并返回切片結(jié)構(gòu)體。runtime.makemap函數(shù)用于創(chuàng)建映射,它會分配一塊哈希表內(nèi)存,并返回映射結(jié)構(gòu)體。runtime.makechan函數(shù)用于創(chuàng)建通道,它會分配一塊通道內(nèi)存,并返回通道結(jié)構(gòu)體。
下面是 make() 函數(shù)的簡化版本的底層實(shí)現(xiàn)原理示例代碼:
package main
import (
"fmt"
"reflect"
"unsafe"
)
func main() {
// 使用 make() 創(chuàng)建一個(gè)切片,并初始化長度為 3 的切片
slice := make([]int, 3)
// 獲得切片的值和長度
sliceValue := reflect.ValueOf(slice)
sliceData := sliceValue.Elem().UnsafeAddr()
sliceLen := sliceValue.Len()
// 輸出切片的值和長度
fmt.Println(sliceData, sliceLen)
}在上述示例代碼中,我們使用了 reflect 包中的 Value、Elem 和 UnsafeAddr 方法來操作切片。我們首先使用 make([]int, 3) 創(chuàng)建一個(gè)長度為 3 的切片 slice,然后通過 reflect.ValueOf 將切片轉(zhuǎn)換為 reflect.Value 類型,再通過 Elem 方法獲取切片的元素,并通過 UnsafeAddr 方法獲取切片的底層數(shù)組的指針,最后通過 Len 方法獲取切片的長度。這樣,我們就可以獲得切片的底層數(shù)組的指針和長度。
請注意,上述示例代碼中使用了 reflect 和 unsafe 包,這是為了演示 make() 的底層實(shí)現(xiàn)原理而引入的,實(shí)際開發(fā)中并不需要經(jīng)常使用這些包。
總結(jié)
通過深入了解 new() 和 make() 函數(shù)的區(qū)別、使用場景以及底層實(shí)現(xiàn)原理,讀者可以更好地理解和運(yùn)用這兩個(gè)函數(shù),并完美解決掉面試官的問題,并在實(shí)際開發(fā)中做出準(zhǔn)確的選擇。
以上就是Go中的new()和make()函數(shù)區(qū)別及底層原理詳解的詳細(xì)內(nèi)容,更多關(guān)于Go new make函數(shù)的資料請關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
詳解Golang time包中的結(jié)構(gòu)體time.Ticker
在日常開發(fā)過程中,會頻繁遇到對時(shí)間進(jìn)行操作的場景,使用 Golang 中的 time 包可以很方便地實(shí)現(xiàn)對時(shí)間的相關(guān)操作,接下來的幾篇文章會詳細(xì)講解 time 包,本文講解一下 time 包中的結(jié)構(gòu)體 time.Ticker,需要的朋友可以參考下2023-08-08
一文搞懂如何實(shí)現(xiàn)Go 超時(shí)控制
這篇文章主要介紹了一文搞懂如何實(shí)現(xiàn)Go 超時(shí)控制,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2021-03-03
Golang實(shí)現(xiàn)驗(yàn)證一個(gè)字符串是否為URL
在實(shí)際開發(fā)過程中,有時(shí)候會遇到?URL?的校驗(yàn)問題,Go?語言中有哪些方法去驗(yàn)證一個(gè)字符串是否滿足?URL?格式呢?本文就來和大家詳細(xì)講講2023-04-04
golang強(qiáng)制類型轉(zhuǎn)換和類型斷言
這篇文章主要介紹了詳情介紹golang類型轉(zhuǎn)換問題,分別由介紹類型斷言和類型轉(zhuǎn)換,這兩者都是不同的概念,下面文章圍繞類型斷言和類型轉(zhuǎn)換的相關(guān)資料展開文章的詳細(xì)內(nèi)容,需要的朋友可以參考以下2021-12-12
基于Go語言實(shí)現(xiàn)高性能文件上傳下載系統(tǒng)
在Web應(yīng)用開發(fā)中,文件上傳下載是一個(gè)非常常見的需求,本文將介紹如何使用Go語言實(shí)現(xiàn)一個(gè)安全、高效的本地文件存儲系統(tǒng),感興趣的小伙伴可以了解下2025-03-03

