table des matières
Troisièmement, la différence entre nouveau et faire
Beaucoup d'amis n'ont pas compris pourquoi il y avait deux fonctions pour allouer de la mémoire lorsqu'ils sont entrés en contact avec Golang pour la première fois: nouveau et faire. Comme le dit le dicton: l'existence est raisonnable. Expliquons en détail la différence entre les deux.
Un, nouveau
Regardez d'abord la déclaration de fonction:
func new(Type) *Type
new est une fonction intégrée de Golang, utilisée pour allouer de la mémoire. Le premier paramètre est le type et la valeur renvoyée est le pointeur du type. Sa valeur est initialisée à "zéro" (valeur zéro correspondant au type, int est initialisé à 0, bool initialisé à false, etc.).
Par exemple:
package main
import "fmt"
func main() {
id := new(int)
name := new(string)
flag := new(bool)
fmt.Printf("id type: %T value: %v\n", id, *id)
fmt.Printf("name type: %T value: %v\n", name, *name)
fmt.Printf("flag type: %T value: %v\n", flag, *flag)
}
Production:
id type: *int value: 0
name type: *string value:
flag type: *bool value: false
Comme on peut le voir dans l'exemple ci-dessus, la valeur «zéro» initialisée diffère selon le type. L'entier est initialisé à 0, la chaîne est initialisée à vide et le type booléen est initialisé à faux.
Deux, fais
Regardez d'abord la déclaration de fonction:
func make(t Type, size ...IntegerType) Type
make est une fonction intégrée de Golang. Elle n'est utilisée que pour allouer et initialiser les types d'objets slice, map et channel. Les trois types sont des structures. La valeur de retour est un type, pas un pointeur.
Structure du code source de tranche:
type slice struct {
array unsafe.Pointer //指针
len int //长度
cap int //容量
}
Mapper la structure du code source:
// A header for a Go map.
type hmap struct {
// Note: the format of the hmap is also encoded in cmd/compile/internal/gc/reflect.go.
// Make sure this stays in sync with the compiler's definition.
count int // # live cells == size of map. Must be first (used by len() builtin)
flags uint8
B uint8 // log_2 of # of buckets (can hold up to loadFactor * 2^B items)
noverflow uint16 // approximate number of overflow buckets; see incrnoverflow for details
hash0 uint32 // hash seed
buckets unsafe.Pointer // array of 2^B Buckets. may be nil if count==0.
oldbuckets unsafe.Pointer // previous bucket array of half the size, non-nil only when growing
nevacuate uintptr // progress counter for evacuation (buckets less than this have been evacuated)
extra *mapextra // optional fields
}
Structure de la source du canal:
type hchan struct {
qcount uint // total data in the queue
dataqsiz uint // size of the circular queue
buf unsafe.Pointer // points to an array of dataqsiz elements
elemsize uint16
closed uint32
elemtype *_type // element type
sendx uint // send index
recvx uint // receive index
recvq waitq // list of recv waiters
sendq waitq // list of send waiters
// lock protects all fields in hchan, as well as several
// fields in sudogs blocked on this channel.
//
// Do not change another G's status while holding this lock
// (in particular, do not ready a G), as this can deadlock
// with stack shrinking.
lock mutex
}
Par exemple:
package main
import "fmt"
func main() {
//map
fmt.Println("map:")
var nameId = make(map[string]int, 0)
fmt.Printf("nameId \ntype: %#v\n", nameId)
nameId["Golang"] = 1
nameId["C++"] = 2
nameId["PHP"] = 3
for name, id := range nameId {
fmt.Printf("name = %v, id = %v\n", name, id)
}
// slice
var hobby = make([]string, 2, 100) // 其中 2是长度,100是容量
hobby[0] = "打篮球"
hobby[1] = "乒乓球"
fmt.Println("\nslice:")
fmt.Printf("length = %v caps = %v\n", len(hobby), cap(hobby))
for _, name := range hobby {
fmt.Println(name)
}
// channel
ch := make(chan int, 3)
ch <- 1
ch <- 2
ch <- 8
close(ch)
fmt.Println("\nchannel:")
for val := range ch { // 遍历数据
fmt.Println(val)
}
}
Production:
[root@localhost test]# go run main.go
map:
nameId
type: map[string]int{}
name = Golang, id = 1
name = C++, id = 2
name = PHP, id = 3
slice:
length = 2 caps = 100
打篮球
乒乓球
channel:
1
2
8
[root@localhost test]#
Troisièmement, la différence entre nouveau et faire
1. new et make sont utilisés pour allouer de la mémoire;
2. Les deux nouveaux et make allouent de la mémoire sur le tas;
3. New alloue de la mémoire pour les types de pointeur et la valeur de retour est un pointeur de type d'allocation. New ne peut pas allouer directement de la mémoire pour la tranche, la carte et le canal;
4. Make n'est utilisé que pour l'initialisation de slice, map et channel, et la valeur de retour est le type lui-même, pas un pointeur;