Maison  >  Article  >  développement back-end  >  Quelle est la différence entre make et new dans le langage go

Quelle est la différence entre make et new dans le langage go

青灯夜游
青灯夜游original
2023-01-09 11:44:079511parcourir

Différences : 1. Make ne peut être utilisé que pour allouer et initialiser des données de types slice, map et chan tandis que new peut allouer n'importe quel type de données. 2. La nouvelle allocation renvoie un pointeur, qui est le type "*Type" tandis que make renvoie une référence, qui est le Type. 3. L'espace alloué par new sera effacé ; une fois que make aura alloué l'espace, il sera initialisé.

Quelle est la différence entre make et new dans le langage go

L'environnement d'exploitation de ce tutoriel : système Windows 7, GO version 1.18, ordinateur Dell G3.

new et make sont des primitives d'allocation de mémoire en langage Go. En termes simples, new alloue uniquement de la mémoire et make est utilisé pour initialiser les tranches, les cartes et les canaux. La fonction

new

new(T) est une fonction intégrée qui alloue de la mémoire. Elle alloue un morceau de mémoire pour chaque type, l'initialise à la valeur zéro et renvoie son adresse mémoire.

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

Quelle est la différence entre make et new dans le langage go

我们可以看到,初始化一个值为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

Comme nous le savons tous, une variable existante peut être affectée à son pointeur.

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

Et si ce n'est pas encore une variable ? Pouvez-vous l'attribuer directement ?

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

Le résultat de l'erreur est tel qu'indiqué dans les commentaires dans le code.

Comment le résoudre ? Cela peut être résolu en fournissant à Go une nouvelle adresse d'initialisation.

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

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

Quelle est la différence entre make et new dans le langage go

Nous pouvons voir que l’initialisation d’une variable pointeur avec une valeur nulle n’est pas une affectation directe. Grâce à

new, un pointeur avec une valeur de 0xc000018030 est renvoyé

pointant vers le type int nouvellement attribué, avec une valeur nulle comme valeur.

De plus, il est important de noter que la valeur zéro est différente selon les types de pointeurs. Pour plus de détails, vous pouvez vous référer à cet article

. Ou vous pouvez parcourir le code ci-dessous.

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)
}
Ce qui précède décrit comment attribuer des valeurs après avoir traité des types ordinaires new(). Voici comment attribuer des valeurs après avoir traité des types composites (tableau, struct). Mais ici, je pense que l'auteur de l'article original a tort, car pour la tranche, la carte et le canal, new ne peut ouvrir que instance de tableau

rrreee

instance de structure

rrreee

    make
  • make est spécialement utilisé pour créer trois types d'allocation de contenu : chan, map et slice, et peut les initialiser. Le type de retour de make est le même type que son argument, et non un pointeur vers celui-ci, car ces trois types de données sont eux-mêmes des types référence.
  • La syntaxe est : func make(t Type, size ...IntegerType) Type Vous pouvez voir que le deuxième paramètre est un paramètre de longueur variable, qui est utilisé pour spécifier la taille de l'alloué. mémoire, comme slice et En d'autres termes, le cap et la longueur doivent être spécifiés (le cap représente la capacité, la longueur représente la longueur, c'est-à-dire la taille qui peut être utilisée), et le cap doit être plus grand que la longueur.

    Je ne vais pas trop vous présenter ici le cap et la longueur de la tranche. Vous pouvez comprendre qu'il y a une maison maintenant. Cette maison est une maison brute. Elle comprend 3 chambres (cap), et 1 d'entre elles a été rénovée. (longueur). ).
  • Pourquoi ne pas utiliser new pour allouer de la mémoire à ces trois types ? Faisons une expérience.

    rrreee

    Vous pouvez voir que la longueur est de 0 lors de l'attribution d'une valeur à la tranche. Quant à la raison spécifique, les amis qui la connaissent peuvent laisser un message dans la zone de commentaire.
Il est donc souvent recommandé d'utiliser make pour réaliser ces trois types de création.

instance de trancherrreeeinstance de carterrreee

instance de canal🎜rrreee🎜🎜🎜Résumé : 🎜🎜🎜🎜la fonction make est utilisée uniquement pour la carte, la tranche et le canal, et ne renvoie pas de pointeurs. Si vous souhaitez obtenir un pointeur explicite, vous pouvez utiliser la nouvelle fonction pour allouer ou utiliser explicitement l'adresse d'une variable. 🎜🎜Les principales différences entre new et make dans le langage Go sont les suivantes : 🎜🎜🎜🎜make ne peut être utilisé que pour allouer et initialiser des données de types slice, map et chan ; new peut allouer n'importe quel type de données. 🎜🎜🎜🎜une nouvelle allocation renvoie un pointeur, qui est le type *Type ; make renvoie une référence, qui est le Type. 🎜🎜🎜🎜new L'espace alloué est effacé ; une fois que make a alloué l'espace, il sera initialisé. 🎜🎜🎜🎜【Recommandations associées : 🎜Tutoriel vidéo Go🎜, 🎜Enseignement de la programmation🎜】🎜

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

Déclaration:
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn