Il fait référence et contient l'emplacement des données, à l'exclusion de lui-même. C'est une structure de données difficile à exprimer avec des mots.
Chaque Go a trois types de référence définis: ** Slice **, ** Map ** et ** Channel **.
Une fonction intégrée qui peut générer trois types de référence pour les canaux de slice map. Étant donné que le modèle diffère selon le type, chaque compréhension est nécessaire.
Ces deux fonctions intégrées peuvent être utilisées efficacement pour trois types de référence, je les garderai donc comme connaissances préalables.
・ ** len ** Vous pouvez vérifier le nombre d'éléments de chaque type. ・ ** cap ** Vous pouvez vérifier la capacité de chaque type.
Une structure de données qui représente quelque chose comme un ** tableau de longueur variable **.
Comme mentionné ci-dessus, vous pouvez générer un type avec la fonction intégrée make.
a := make([]int, 5)
a[0] = 1
fmt.Println(a) //[1 0 0 0 0]
Une tranche de type int d'une capacité de 5 est générée et une valeur d'index arbitraire est spécifiée. La méthode et le comportement de génération sont très similaires au type de tableau, mais contrairement au type de tableau, il est affecté par un processus lors de l'échange d'appels entre fonctions.
Les tranches ont des littéraux que vous pouvez générer sans utiliser make.
a := []int{ 0, 1, 2, 3, 4 }
fmt.Println(a) //[0 1 2 3 4]
Il existe une fonction appelée ** expression de tranche simple ** et ** expression de tranche complète ** qui prend des paramètres basés sur des tranches existantes et crée de nouvelles tranches.
Tout d'abord, la formule de tranche simple prend une plage de paramètres liés à l'index de la tranche, extrait une partie de la tranche représentée par ce paramètre et crée une nouvelle tranche.
a := []int{ 0, 1, 2, 3, 4 }
fmt.Println(a[0:4]) //[0 1 2 3]
Il est nécessaire de comprendre la méthode de description car il existe des variations en fonction des paramètres à prendre et ainsi de suite.
Ensuite, contrairement au type de tranche simple, le type de tranche complet peut prendre trois paramètres: ** low **: ** high **: ** max **.
a := []int{ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }
b := a[2:6:8]
fmt.Println(len(b)) //4
fmt.Println(cap(b)) //6
La capacité d'un type de tableau normal ou d'une tranche est déterminée par ** nombre d'éléments - faible valeur **, mais si vous prenez le paramètre sous la forme d'un type de tranche complète, ** max - faible valeur ** Il y a une différence par laquelle la capacité est déterminée.
Vous pouvez également faire référence à la chaîne dans l'une ou l'autre des expressions de tranche. Cependant, pour les caractères multi-octets qui ne peuvent pas être exprimés en ASCII, il est nécessaire de spécifier la plage d'index dans la chaîne d'octets car [] octets sont utilisés comme unité.
Voyons quel type de fonctions les fonctions intégrées ** append ** et ** copy ** ont. ・ ** append ** Il s'agit d'une fonction qui vous permet d'ajouter des éléments de tranche.
append.go
a := make([]int, 0, 0)
fmt.Println(cap(a))
a = append(a, []int{ 1, 2, 3 }...)
fmt.Println(a) //[1, 2, 3]
fmt.Println(cap(a)) //4
a = append(a, []int{ 4, 5, 6 }...)
fmt.Println(a) //[1, 2, 3, 4, 5, 6]
fmt.Println(cap(a)) //8
Un élément est ajouté à la fin d'une tranche avec 0 élément et 0 capacité, et les fluctuations de capacité sont confirmées. A partir de ce programme, les tranches ont la propriété d'être automatiquement étendues lorsque la capacité est dépassée et que des éléments sont ajoutés. À première vue, il semble qu'il a doublé, mais il est important de noter qu'il n'est pas doublé sans équivoque car cela dépend du prix de combat et de la durée d'exécution.
Dans le cas ci-dessus, puisque les métadonnées sont prises comme valeur de retour de append, l'ajout est reflété et la valeur peut être sortie avec cap, mais même si l'ajout est effectué indirectement aux métadonnées, il n'est pas reflété. Il a une nature.
append.go
func test(a []int) {
a = append(a, 3)
}
func main() {
b := make([]int, 1, 2)
test(b)
fmt.Println(cap(b)) //2
}
copy.go
a := []int{ 1, 2, 3, 4, 5 }
b := []int{ 6, 7, 8 }
fmt.Println(copy(a, b), a) //3 [6 7 8 4 5]
Le nombre d'éléments copiés et les éléments copiés sont affichés. De cette manière, l'élément est écrasé depuis le début de la cible de copie. Même si le nombre d'éléments à copier dépasse le nombre d'éléments à copier, le nombre d'éléments à copier sera copié.
Vous pouvez également copier des types de chaîne, mais vous devez considérer qu'ils sont copiés octet par octet, comme décrit ci-dessus pour les expressions de tranche.
Une structure de données qui représente quelque chose comme un ** tableau associatif **.
Les cartes peuvent également être générées avec la fonction intégrée make, en suivant l'exemple.
a := make(map[int]string)
a[1] = "test1"
a[2] = "test2"
fmt.Println(a) //map[1:test1 2:test2]
La valeur de clé de type int et le type d'élément de type chaîne sont définis, et la valeur de clé et l'élément en fonction du type sont affectés et sortis. De plus, pour le nombre d'éléments, prendre un indice pour allouer une zone mémoire dans le deuxième argument peut être utile lorsque la carte est grande.
Les cartes ont également des littéraux à générer sans utiliser make.
a := map[int]string{ 1: "test1", 2: "test2" }
fmt.Println(a)
Les éléments peuvent être écrits sur plusieurs lignes pour une meilleure lisibilité, mais en raison des caractéristiques de Go, la dernière valeur doit se terminer par une virgule pour signifier la continuation.
Vous pouvez également générer des tranches dans la carte.
a := map[int][]int{
1: []int{1}
2: []int{2}
}
fmt.Println(a) //map[1:[1] 2:[2]]
En passant, [] int dans la spécification d'élément peut être omis, donc je pense qu'il n'y a pas de mérite particulier à écrire [] int.
En affectant à une variable comme ** a [1] **, vous pouvez faire référence à l'élément de valeur clé correspondant, mais dans Go, le type de base n'a pas l'état ** nil **. Par conséquent, si la valeur initiale du type est définie dans l'élément, elle sera traitée tout en la conservant. Cependant, vous pouvez contourner ce problème en utilisant un idiome qui affecte deux variables.
a := map[int]string{ 1: "test1", 2: "test2" }
if a, ok := a[1]; ok {
fmt.Printf("%v, %v\n", a, ok) //test1, true
} else {
fmt.Printf("%v, %v\n", a, ok) //※ , false
Dans le programme ci-dessus, la deuxième variable évalue s'il existe un élément correspondant à la clé et est affectée comme un type booléen. Le traitement de branche est effectué selon l'expression conditionnelle et il est généré. Bien sûr, si la valeur de clé assignée n'existe pas dans la carte, else sera exécuté et une chaîne vide et false seront affichés.
delete Une fonction intégrée pour supprimer des éléments de la carte.
a := map[int]string{ 1: "test1", 2: "test2" }
fmt.Println(len(a)) //2
delete(a, 2)
fmt.Println(len(a)) //1
** delete ** Le changement du nombre d'éléments avant et après est comparé à l'aide de len. Avant la suppression, le résultat est égal au nombre d'éléments de la carte, mais en utilisant la suppression, vous pouvez voir que le nombre d'éléments est réduit. Puisque la suppression peut être supprimée en spécifiant une valeur de clé arbitraire, cela signifie que "test2" dont la valeur de clé est 2 est supprimé dans le programme ci-dessus.
À propos, bien qu'il y ait une capacité pratique dans la carte, le cap ne peut pas être utilisé en raison de sa nature.
[Article précédent (À propos de la syntaxe de contrôle)](https://qiita.com/noa-1129/items/819f4a8d81dcdd0c19cd#%E3%82%B4%E3%83%AB%E3%83%BC%E3%83% C'est une structure de données qui est responsable de l'envoi et de la réception des données entre les goroutines, résumée en 81% E3% 83% B3).
Il existe un type de canal dans un canal.
var a chan int
Comme nous le verrons plus tard, vous pouvez spécifier des sous-types tels que ** canaux de réception uniquement ** et ** canaux d'envoi uniquement **. Si non spécifié, la transmission et la réception sont possibles.
Lorsqu'il est généré par make, ce sera comme suit.
a := make(chan int, 5)
Vous pouvez spécifier la quantité d'espace qui peut temporairement contenir des données, appelée ** taille de la mémoire tampon **.
Utilisez les canaux pour envoyer et recevoir des données.
a := make(chan int, 5)
a <- 1 //Envoyer
a <- 2 //Envoyer
fmt.Println(cap(a)) //5
fmt.Println(len(a)) //2
b := <-a //Recevoir
fmt.Println(b) // 1
fmt.Println(cap(a)) //5
fmt.Println(len(a)) //1
Dans le programme ci-dessus, un canal avec une taille de tampon de 5 est généré, et les données dans le canal sont comparées lorsque le canal est transmis et reçu. Tout d'abord, en regardant la capacité et le nombre d'éléments lorsque les valeurs de 1 et 2 sont envoyées au canal a, la capacité est la taille de la mémoire tampon, donc la valeur est 5, et comme deux valeurs sont envoyées, le nombre d'éléments est 2. Devenir. Par conséquent, une valeur est reçue dans la variable b. De cette façon, la capacité ne change pas, mais le nombre d'éléments est réduit d'un. De plus, puisque 1 est sorti de la variable b, on peut voir que les données sont envoyées et reçues dans la relation ** premier entré, premier sorti **.
Maintenant, envoyons et recevons des données entre les goroutines.
func test(a <- chan int) {
for {
b, ok := <-a
if ok == false {
break
}
fmt.Println(b) //1
} //2
} //3
//4
func main() {
a := make(chan int)
go test(a)
b := 1
for b < 5 {
a <- b
b++
}
close(a)
}
Dans le programme ci-dessus, le test de fonction pour recevoir le canal qui prend un argument arbitraire est défini, et lorsque le canal a est fermé (renvoie une valeur fausse), un traitement de branche qui interrompt la boucle pendant la sortie est effectué. Je suis. Ensuite, la fonction main partage le goroutine qui génère le canal a utilisé par le test de fonction et continue d'envoyer la variable b qui s'incrémente jusqu'à ce que la valeur devienne inférieure à 5, et le test de fonction est la valeur reçue du canal. Continue à être sortie. Puisqu'il est fermé lorsque la transmission des données est terminée, lorsque la valeur est égale ou supérieure à 5, le deuxième argument, ok, renvoie false et le traitement se termine.
S'il y a deux canaux ou plus qui représentent la réception d'une variable, le goroutine s'arrêtera si le canal précédent ne peut pas recevoir. La syntaxe de contrôle select peut résoudre ce problème.
a := make(chan int, 1)
b := make(chan int, 1)
b <- 5
select {
case <- a:
fmt.Println("x is done")
case <- b:
fmt.Println("y is done") //production
default:
fmt.Println("?")
}
La variable a a un canal généré, mais ne peut pas être reçue car elle n'a pas été envoyée. Normalement, le goroutine s'arrêterait à ce stade, mais comme il utilise la syntaxe de sélection, le processus continue. De plus, si le traitement de plusieurs cas réussit, il sera exécuté de manière aléatoire.
Cette fois, j'ai résumé le type de référence! !! Le type de référence a beaucoup de contenu et tous les idiomes qui apparaissent fréquemment dans les programmes Go, donc je veux bien le comprendre.
Auteur Aiga Matsuo [Shoyusha Starting Go Language](https://www.shoeisha.co.jp/search?search=%E3%82%B9%E3%82%BF%E3%83%BC%E3%83%86% E3% 82% A3% E3% 83% B3% E3% 82% B0Go% E8% A8% 80% E8% AA% 9E)
Recommended Posts