Heim  >  Artikel  >  Backend-Entwicklung  >  Was ist der Unterschied zwischen make und new in der Go-Sprache?

Was ist der Unterschied zwischen make und new in der Go-Sprache?

青灯夜游
青灯夜游Original
2023-01-09 11:44:079488Durchsuche

Unterschiede: 1. Make kann nur zum Zuweisen und Initialisieren von Daten der Typen Slice, Map und Chan verwendet werden, während new jede Art von Daten zuordnen kann. 2. Die neue Zuweisung gibt einen Zeiger vom Typ „*Type“ zurück, während make eine Referenz vom Typ „Type“ zurückgibt. 3. Der von new zugewiesene Speicherplatz wird gelöscht. Nachdem make den Speicherplatz zugewiesen hat, wird er initialisiert.

Was ist der Unterschied zwischen make und new in der Go-Sprache?

Die Betriebsumgebung dieses Tutorials: Windows 7-System, GO Version 1.18, Dell G3-Computer.

new und make sind Grundelemente für die Speicherzuweisung in der Go-Sprache. Einfach ausgedrückt: new weist nur Speicher zu und make wird zum Initialisieren von Slices, Maps und Kanälen verwendet. Die Funktion

new

new(T) ist eine integrierte Funktion, die jedem Typ einen Speicher zuweist, ihn auf den Wert Null initialisiert und seine Speicheradresse zurückgibt.

Die Syntax lautet func new(Type) *Typefunc 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 提供 new 初始化地址来解决。

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 指针指向了一个匿名变量
}

Was ist der Unterschied zwischen make und new in der Go-Sprache?

我们可以看到,初始化一个值为nil的指针变量并不是直接赋值。通过new返回一个值为0xc000018030 的指针指向新赋值的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()后如何赋值,这里是处理复合类型(array、struct)后如何赋值。但是在这里,我认为原文的作者讲述有错误,因为对 slice,map 和 channel 来说,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
}

make

make 专门用于创建 chan,map 和 slice 三种类型的内容分配,并且可以初始化它们。make 的返回类型与其参数的类型相同,而不是指向它的指针,因为这三种数据类型本身就是引用类型。

其语法为:func make(t Type, size ...IntegerType) Type

Wie wir alle wissen, kann eine vorhandene Variable ihrem Zeiger zugewiesen werden.

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
}
}

Und was ist, wenn es noch keine Variable ist? Kann man es direkt zuordnen?

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)) 
}

Das Fehlerergebnis ist wie in den Kommentaren im Code gezeigt.

Wie kann man es lösen? Dies kann gelöst werden, indem Go eine neue Initialisierungsadresse bereitstellt.

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

	fmt.Println(mapInstance) // map[第一名:张三 第三名:王五 第二名:李四]
}

Was ist der Unterschied zwischen make und new in der Go-Sprache?

Wir können sehen, dass die Initialisierung einer Zeigervariablen mit dem Wert Null keine direkte Zuweisung ist. Through

new gibt einen Zeiger mit dem Wert 0xc000018030

zurück, der auf den neu zugewiesenen int-Typ zeigt, mit dem Wert Null als Wert.

Außerdem ist zu beachten, dass der Nullwert für verschiedene Zeigertypen unterschiedlich ist. Einzelheiten finden Sie in diesem Artikel

. Oder Sie können den Code unten durchsuchen.

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)
}
Oben wird beschrieben, wie Werte nach der Verarbeitung gewöhnlicher Typen new() zugewiesen werden. Hier erfahren Sie, wie Sie Werte nach der Verarbeitung zusammengesetzter Typen (Array, Struktur) zuweisen. Aber hier liegt meiner Meinung nach der Autor des Originalartikels falsch, denn für Slice, Map und Channel kann new nur Array-Instanz

rrreee

Strukturinstanz

rrreee

    make
  • öffnen

    make wird speziell zum Erstellen von drei Arten der Inhaltszuordnung verwendet: Chan, Map und Slice und kann diese initialisieren. Der Rückgabetyp von make ist derselbe Typ wie sein Argument und kein Zeiger darauf, da diese drei Datentypen selbst Referenztypen sind.
  • Die Syntax lautet: func make(t Type, size ...IntegerType) Type Sie können sehen, dass der zweite Parameter ein Parameter variabler Länge ist, der zur Angabe der Größe des zugewiesenen Parameters verwendet wird B. Slice und Mit anderen Worten, die Obergrenze und die Länge müssen angegeben werden (die Obergrenze stellt die Kapazität dar, die Länge stellt die Länge dar, dh die Größe, die verwendet werden kann), und die Obergrenze muss größer als die Länge sein.

    Ich werde hier nicht zu viel über die Obergrenze und die Länge des Abschnitts sagen. Sie können verstehen, dass es sich bei diesem Haus um ein Rohhaus handelt, von dem eines renoviert wurde (Länge). ).
  • Warum nicht new verwenden, um Speicher für diese drei Typen zuzuweisen? Machen wir ein Experiment.

    rrreee

    Sie können sehen, dass die Länge 0 beträgt, wenn Sie Slice einen Wert zuweisen. Was den konkreten Grund betrifft, können Freunde, die es wissen, eine Nachricht im Kommentarbereich hinterlassen.
Daher wird oft empfohlen, make zu verwenden, um diese drei Arten der Erstellung durchzuführen.

Slice-InstanzrrreeeKarteninstanzrrreee

Kanalinstanz🎜rrreee🎜🎜🎜Zusammenfassung: 🎜🎜🎜🎜make-Funktion wird nur für Map, Slice und Channel verwendet und gibt keine Zeiger zurück. Wenn Sie einen expliziten Zeiger erhalten möchten, können Sie die neue Funktion zum Zuweisen verwenden oder explizit die Adresse einer Variablen verwenden. 🎜🎜Die Hauptunterschiede zwischen new und make in der Go-Sprache sind wie folgt: 🎜🎜🎜🎜make kann nur zum Zuweisen und Initialisieren von Daten der Typen Slice, Map und Chan verwendet werden; new kann jede Art von Daten zuordnen. 🎜🎜🎜🎜Neue Zuweisung gibt einen Zeiger zurück, der vom Typ *Type ist; make gibt eine Referenz zurück, der Typ ist. 🎜🎜🎜🎜new Der zugewiesene Speicherplatz wird gelöscht. Nachdem make den Speicherplatz zugewiesen hat, wird er initialisiert. 🎜🎜🎜🎜【Verwandte Empfehlungen: 🎜Go-Video-Tutorial🎜, 🎜Programmierunterricht🎜】🎜

Das obige ist der detaillierte Inhalt vonWas ist der Unterschied zwischen make und new in der Go-Sprache?. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

Stellungnahme:
Der Inhalt dieses Artikels wird freiwillig von Internetnutzern beigesteuert und das Urheberrecht liegt beim ursprünglichen Autor. Diese Website übernimmt keine entsprechende rechtliche Verantwortung. Wenn Sie Inhalte finden, bei denen der Verdacht eines Plagiats oder einer Rechtsverletzung besteht, wenden Sie sich bitte an admin@php.cn