日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 人文社科 > 生活经验 >内容正文

生活经验

Go 学习笔记(30)— Go 语言 make 和 new 的区别

發布時間:2023/11/27 生活经验 27 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Go 学习笔记(30)— Go 语言 make 和 new 的区别 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

Go 語言中 newmake 是兩個內置函數,主要用來創建并分配類型的內存。在我們定義變量的時候,可能會覺得有點迷惑,不知道應該使用哪個函數來聲明變量,其實他們的規則很簡單:

  • new 只分配內存
  • make 只能用于 slicemapchannel 的初始化

1. new

Go 語言中, 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() 函數可以創建一個對應類型的指針,創建過程會分配內存,被創建的指針指向默認值。

注意, Go 中的 new 關鍵字并不是聲明變量,而是返回該類型的指針

a := new(int) //這時候 a 是一個*int 指針變量

使用 new 函數為變量分配內存空間。

var sum *int
sum = new(int) //分配空間
*sum = 98
fmt.Println(*sum)

當然, new 函數不僅僅能夠為系統默認的數據類型,分配空間,自定義類型也可以使用 new 函數來分配空間,如下所示:

type Student struct {name stringage int
}var s *Student
s = new(Student) //分配空間
s.name ="dequan"fmt.Println(s)

這里如果我們不使用 new 函數為自定義類型分配空間(將第 7 行注釋),就會報錯:

panic: runtime error: invalid memory address or nil pointer dereference
[signal SIGSEGV: segmentation violation code=0x1 addr=0x0 pc=0x80bd277]
goroutine 1 [running]:

這就是 new 函數,它返回的永遠是類型的指針,指針指向分配類型的內存地址。

使用示例:

package main// 導入系統包
import ("fmt"
)func main() {str := new(string)*str = "hello,world"value := new(int)*value = 10fmt.Println(*str)	// hello,worldfmt.Println(*value)	// 10}

new 函數用來創建某一個類型的指針型對象。理論上,一個數據類型,只要能夠被訪問,就可以使用 new 函數來創建這個類型的指針型對象。下邊來看一段示例,使用 new 函數創建基本類型的指針型對象。

package main
import ("fmt"
)
type demo struct{}
func main() {var str = new(string)fmt.Println("string pointer", str)var num = new(int)fmt.Println("int pointer", num)var de = new(demo)fmt.Println("struct pointer", de)
}

在調用 new 函數時,將類型名作為參數即可創建出這個類型的指針型對象。

Golang 中存在幾種特殊的情況。如使用 new 創建 chan 類型指針型對象,但是仍然需要調用 make 來給 chan 類型變量分配容量。

package main
import ("fmt""time"
)
func main() {// 創建通道類型指針型對象var ch = new(chan int)// 給對象分配容量,容量為1*ch = make(chan int)// 開啟協程,從通道中讀取數據go func() {fmt.Println(<-(*ch))}()// 向通道中寫入數據*ch <- 8time.Sleep(time.Second * 1)
}

如果使用 new 創建通道類型變量后,不使用 make 來分配容量,當向通道中寫入信息或從通道中讀取信息時,將會出現下邊錯誤信息:

... [chan send (nil chan)]:
... [chan receive (nil chan)]

雖然 new 關鍵字可以創建任何類型的指針型對象,但是由于某些特殊類型的對象被創建后,需要進行更多的初始化工作,所以 Golang 中引入了 make 函數,通過 make 來創建這些特殊類型的對象。這些特殊類型就是:切片類型、通道類型、字典類型。

另一個創建變量的方法是調用內建的 new 函數。表達式 new(T) 將創建一個 T 類型的匿名變量,初始化為 T 類型的零值,然后返回變量地址,返回的指針類型為*T

p := new(int)   // p, *int 類型, 指向匿名的 int 變量
fmt.Println(*p) // "0"
*p = 2          // 設置 int 匿名變量的值為 2
fmt.Println(*p) // "2"

new 創建變量和普通變量聲明語句方式創建變量沒有什么區別,除了不需要聲明一個臨時變量的名字外,我們還可以在表達式中使用 new(T) 。換言之, new 函數類似是一種語法糖,而不是一個新的基礎概念。

下面的兩個 newInt 函數有著相同的行為:

func newInt() *int {return new(int)
}
func newInt() *int {var dummy intreturn &dummy
}

每次調用 new 函數都是返回一個新的變量的地址,因此下面兩個地址是不同的:

p := new(int)
q := new(int)
fmt.Println(p == q) // "false"

當然也可能有特殊情況:如果兩個類型都是空的,也就是說類型的大小是 0,例如struct{}[0]int,有可能有相同的地址(依賴具體的語言實現)(譯注:請謹慎使用大小為 0 的類型,因為如果類型的大小為 0 的話,可能導致 Go 語言的自動垃圾回收器有不同的行為,具體請查看runtime.SetFinalizer函數相關文檔)。

new 函數使用通常相對比較少,因為對于結構體來說,直接用字面量語法創建新變量的方法會更靈活。

由于 new 只是一個預定義的函數,它并不是一個關鍵字,因此我們可以將 new 名字重新定義為別的類型。例如下面的例子:

func delta(old, new int) int { return new - old }

由于 new 被定義為 int 類型的變量名,因此在 delta 函數內部是無法使用內置的 new 函數的。

2. make

make 也是用于內存分配的,但是和 new 不同,它只用于 chanmap 以及 slice 的內存創建,而且它返回的類型就是這三個類型本身,而不是他們的指針類型,因為這三種類型就是引用類型,所以就沒有必要返回他們的指針了。

Go 語言中, make 函數的描述如下:

// 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, 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 函數的 t 參數必須是 chan (通道)、 map (字典)、 slice (切片)中的一個,并且返回值也是類型本身。

make 用于給切片、通道、字典類型變量分配容量空間。給不同的類型變量分配空間時, make 參數不一樣。下邊來介紹一下不同類型使用 make 時的不同用法:

注意: make 函數只用于 mapslicechannel ,并且不返回指針。如果想要獲得一個顯式的指針,可以使用 new 函數進行分配,或者顯式地使用一個變量的地址。

使用 make 的好處是可以使用很短的代碼初始化一個長度很大的值,示例如下:

ips := make([]string, 100)

上述代碼表示初始化為一個元素類型為 string 且長度為 100 的切片值,用 make 函數初始化的切片值中的每一個元素值都會是其元素類型的零值,這里 ips 的 100 個元素都是空字符串 “”。

使用 make 給切片類型變量分配容量空間:

  1. 給字符串類型切片分配 4 個容量空間。
var arr = make([]string,4)
  1. 給字符串類型切片分配 10 個容量空間,且設置切片長度為 5,也就是設置切片前 5 個元素已經被使用,如果使用 append 向切片中追加元素,新追加的元素將會從第 6 個位置算起(下標為 5)。
var arr = make([]string,5,10)
  1. 使用 make 給通道類型變量分配容量空間,創建了一個不帶緩沖的通道。
var ch = make(chan int)
  1. 使用 make 給通道類型變量分配容量空間,創建了一個帶 10 個緩沖的通道。
var ch = make(chan int, 10)
  1. 使用 make 給字典類型變量分配容量空間
var mp = make(map[string]int)

給字典類型變量分配空間,不需要指定容量,如果在第二個參數中指定容量,這個容量值也會被忽略。如下邊寫法:

// 容量10被忽略
var mp = make(map[string]int,10)

雖然在給 map 類型變量分配容量時,指定了長度 10,但由于 map 類型變量能夠裝載的數據量與系統內存有關,所以給 map 類型變量設置容量的做法將會被忽略。

請牢記一點:make 函數只能初始化字典(map),切片(slice),通道(chan)類型。

Go 語言中的 newmake 主要區別如下:

  • make 只能用來分配及初始化類型為 slicemapchan 的數據。 new 可以分配任意類型的數據;
  • new 分配返回的是指針,即類型 *Typemake 返回引用,即 Type
  • new 分配的空間被清零。 make 分配空間后,會進行初始化;

總結

以上是生活随笔為你收集整理的Go 学习笔记(30)— Go 语言 make 和 new 的区别的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。