ホームページ > バックエンド開発 > Golang > Go言語のmakeとnewの違いは何ですか

Go言語のmakeとnewの違いは何ですか

青灯夜游
リリース: 2023-01-09 11:44:07
オリジナル
9549 人が閲覧しました

違い: 1. Make は、slice、map、chan タイプのデータの割り当てと初期化にのみ使用できますが、new は任意のタイプのデータを割り当てることができます。 2. 新しい割り当ては型「*Type」であるポインタを返しますが、make は参照である Type を返します。 3. new によって割り当てられたスペースはクリアされ、make によってスペースが割り当てられた後、初期化されます。

Go言語のmakeとnewの違いは何ですか

このチュートリアルの動作環境: Windows 7 システム、GO バージョン 1.18、Dell G3 コンピューター。

new と make は、Go 言語のメモリ割り当てのプリミティブです。簡単に言うと、new はメモリを割り当てるだけであり、make はスライス、マップ、チャネルの初期化に使用されます。

#new

new(T) 関数はメモリを割り当てる組み込み関数で、型ごとにメモリを割り当て、値をゼロに初期化し、そのメモリアドレスを返します。

構文は

func new(Type) *Type

ご存知のとおり、既存の変数をそのポインターに割り当てることができます。

var p int
var v *int
v = &p
*v = 11
fmt.Println(*v)
ログイン後にコピー

では、まだ変数ではない場合はどうすればよいでしょうか?直接割り当ててもらえますか?

func main() {
	var v *int
	*v = 8
	fmt.Println(*v)

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

	// goroutine 1 [running]:
	// main.main()
	// 	/tmp/sandbox1410772957/prog.go:9 +0x16
}
ログイン後にコピー

エラー結果はコード内のコメントに示されているとおりです。 ######の解き方?これは、Go が新しい初期化アドレスを提供することで解決できます。

func main() {
	var v *int
	// v 是一个 int 类型的指针,v 的地址和 v 的值  0xc0000ba018 <nil>
	fmt.Println("v 是一个 int 类型的指针,v 的地址和 v 的值 ", &v, v)   
	// 分配给 v 一个指向的变量             
	v = new(int)    
	// v 是一个 int 类型的指针,v 的地址和 v 的值  0xc0000ba018 0xc000018030 0,此时已经分配给了 v 指针一个指向的变量,但是变量为零值                                                  
	fmt.Println("v 是一个 int 类型的指针,v 的地址, v 的值和 v 指向的变量的值 ", &v, v, *v) 
	*v = 8
	// v 是一个 int 类型的指针,v 的地址和 v 的值  0xc0000ba018 0xc000018030 8,此时又像这个变量中装填了一个值 8
	fmt.Println("v 是一个 int 类型的指针,v 的地址, v 的值和 v 指向的变量的值 ", &v, v, *v) 
	
	// 整个过程可以理解为给 v 指针指向了一个匿名变量
}
ログイン後にコピー

ポインタ変数を nil の値で初期化することは、直接の代入ではないことがわかります。値 0xc000018030 から Go言語のmakeとnewの違いは何ですかnew までのポインタを返します。

は新しく割り当てられた int 型を指し、ゼロ値はその値です。

さらに、ゼロ値はポインター型によって異なることに注意することが重要です。詳細については、この記事

を参照してください。または、以下のコードを参照することもできます。

type Name struct {
    P string
}
var av *[5]int
var iv *int
var sv *string
var tv *Name

av = new([5]int)
fmt.Println(*av) //[0 0 0 0 0 0]
iv = new(int)
fmt.Println(*iv) // 0
sv = new(string) 
fmt.Println(*sv) //
tv = new(Name)
fmt.Println(*tv) //{}
ログイン後にコピー
上記は通常の型new()の処理後に値を代入する方法ですが、ここでは複合型(配列、構造体)の処理後に値を代入する方法を説明します。しかしここで、元の記事の著者は間違っていると思います。スライス、マップ、チャネルの場合、new は

配列インスタンス

func main() {
	// 声明一个数组指针
	var a *[5]int
	fmt.Printf("a: %p %#v \n", &a, a) //a: 0xc04200a180 [5]int{0, 0, 0, 0, 0}
	// 分配一个内存地址给 a(数组指针)指向
	a = new([5]int)
	fmt.Printf("a: %p %#v \n", &a, a) //av: 0xc000074018 &[5]int{0, 0, 0, 0, 0}
	// 修改这个数组中的值
	(*a)[1] = 8
	fmt.Printf("a: %p %#v \n", &a, a) //av: 0xc000006028 &[5]int{0, 8, 0, 0, 0}
}
ログイン後にコピー

構造インスタンス

type mystruct struct {
	name string
	age  int
}

func main() {
	var people *mystruct
	people = new(mystruct)
	people.name = "zhangsan"
	people.age = 11

	fmt.Printf("%v, %v", people.name, people.age) // zhangsan, 11
}
ログイン後にコピー

しか開けないからです。

makemake は、chan、map、slice の 3 種類のコンテンツ割り当てを作成するために特別に使用され、それらを初期化できます。これら 3 つのデータ型自体が参照型であるため、make の戻り値の型は引数へのポインターではなく、引数と同じ型です。

構文は:

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

です。2 番目のパラメーターは可変長パラメーターであり、スライスの場合、cap と length を指定する必要があり (cap は容量を表し、length は長さ、つまり使用できるサイズを表します)、cap は length より大きい必要があります。

ここではキャップとスライスの長さについてはあまり紹介しません。今家があることがわかります。この家はラフな家です。すべての部屋が 3 部屋 (キャップ) で、 1部屋(長さ)。

これら 3 つのタイプにメモリを割り当てるために new を使用しないのはなぜでしょうか?実験をしてみましょう。

func main() {
	var s *[]int
	fmt.Printf("s 的地址是: %p, s 的值是 %p\n", &s, s) // s 的地址是: 0xc00000e028, s 的值是 0x0
	s = new([]int)
	fmt.Printf("s 的地址是: %p, s 的值是 %p\n", &s, s) // s 的地址是: 0xc00000e028, s 的值是 0xc00011a018
	(*s)[0] = 1
	fmt.Println("s 的地址是: %p, s 的值是 %p\n", &s, s) // panic: runtime error: index out of range [0] with length 0
}
}
ログイン後にコピー

スライスに値を代入すると長さが0になっていることがわかりますが、具体的な理由については、それを知っている友達がコメント欄にメッセージを残してくれると思います。

したがって、多くの場合、これら 3 種類の作成を実行するには make を使用することが推奨されます。

スライス インスタンス

func main() {
	// 第一个 size 是 length,第二个 size 是 cap
	a := make([]int, 5, 10)
	// a: 0xc00011a018 []int{0, 0, 0, 0, 0},cap: 10, length: 5 
	fmt.Printf("a: %p %#v,cap: %d, length: %d \n", &a, a, cap(a), len(a)) 
}
ログイン後にコピー

マップ インスタンス

func main() {
	// 第一个 string 是 key,第二个 string 是 value
	mapInstance := make(map[string]string, 5)
	mapInstance["第一名"] = "张三"
	mapInstance["第二名"] = "李四"
	mapInstance["第三名"] = "王五"

	fmt.Println(mapInstance) // map[第一名:张三 第三名:王五 第二名:李四]
}
ログイン後にコピー

チャネル インスタンス

func countNum(temp int, ch chan int) {
	i := temp + 1
	ch <- i
	fmt.Println("已经将 i 发往通道 c 中")
}

func main() {
	ch := make(chan int)
	go countNum(1, ch)
	res := <-ch
	fmt.Println("已经从 ch 中获取 i 并保存在 res 中")
	fmt.Println("res 是", res)
}
ログイン後にコピー

概要:

make 関数はマップ、スライス、チャネルにのみ使用され、ポインターを返しません。明示的なポインタを取得したい場合は、新しい関数を使用して割り当てるか、変数のアドレスを明示的に使用します。

Go 言語における new と make の主な違いは次のとおりです。

make は、slice、map、および chan 型のデータの割り当てと初期化にのみ使用できます。 ; new は任意のタイプのデータを割り当てることができます。
  • 新しい割り当ては、*Type 型であるポインタを返します。make は、Type である参照を返します。
  • new によって割り当てられたスペースはクリアされ、make によってスペースが割り当てられた後、初期化されます。
  • [関連する推奨事項:
  • Go ビデオ チュートリアル

プログラミング教育 ]

以上がGo言語のmakeとnewの違いは何ですかの詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

関連ラベル:
ソース:php.cn
このウェブサイトの声明
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。
人気のチュートリアル
詳細>
最新のダウンロード
詳細>
ウェブエフェクト
公式サイト
サイト素材
フロントエンドテンプレート