Go langage
Mémo go
Uniquement des notes sur ce qui est “original” dans le langage “go”, par rapport aux autres langages.
Variables
Déclaration
Par rapport à tous les autres langages, il faut le faire à l’envers :
var x int
Et pour un tableau : var [nom] [[longueur]][type]
, exemple :
var s [3]int
Initialisation avec des valeurs
Pas d’explication, un exemple direct suffit : arr := [2]int{2, 4}
Inférence de type
Une déclaration complète d’une variable serait var i int = 12
Une déclaration ultra simplifiée acceptable est i := 12
et dans ce cas, Go va tenter de deviner le type (“type inference”).
Comparaison de tableaux
La déclaration de variables se fait toujours en précisant la longueur, et au moment de comparer, il faut que les tableaux aient exactement la même longueur, sinon on aura une erreur. C’est pour cela que les tableaux sont moins utilisés que le type slice
.
Comparaison = avoir des types identiques
Go n’essaie jamais de transformer les variables en booléens pour pouvoir les comparer, c’est à nous transformer une variable ou l’autre de manière à ce qu’elles aient toujours le même type.
Création d’une variable dans un “if”
Exemple direct : if b:= a / 2; b > 5 {...} else {...}
La variable b n’existera que dans le bloc if / else.
Boucle for / range
s := "Bonjour"
for k, v := range s {
fmt.Println(k, v, string(v))
}
k
correspond à l’index, et n’est pas toujours incrémenté que de 1, selon l’encodage. C’est la méthode à utiliser pour parcourir une chaîne en utf8. Car via un classique for
, Go parcourra la chaîne “à la” C, c’est à dire que un caractère = un octet (ce qui n’est pas le cas en utf8).
Switch / case
Par défaut, les “break
” sont implicites, pas besoin de les mettre. Si on veut exécuter l’instruction du “case
” suivant (= comme en C ou JavaScript), il faut le dire explicitement via “fallthrough
“.
Il est possible de créer une variable qui ne vivra que le temps du switch / case
, exemple :
switch l := len(word); word {
...blabla...
}
Contrairement aux autres langages, il ne faut pas mettre plusieurs case
d’affilée pour gérer plusieurs cas au même endroit, il suffit de les séparer par une virgule, exemple pour continuer le précédent :
switch l := len(word); word {
case 1 < l && l < 10, word == "ok":
fmt.Println("Soit mot : 1 < longueur < 10, soit il vaut 'ok'")
}
Fonctions
Appels
Tous les appels de fonction sont par valeur. Jamais par référence. Nombre, booléen, ainsi que les tableaux.
Retours
Le type résultat de retour est après les parenthèses des paramètres et avant l’accolade ouvrante :
func mult(a, b) int {
return a + b
}
Vous pouvez renvoyer plusieurs valeurs ! Les résultats de retour sont entre parenthèse après les parenthèses des paramètres et avant l’accolade ouvrante :
func divAndRemainder(a, b) (int, int) {
return a / b, a % b
}
d, r := divAndRemainder(2, 3)
d, _ := divAndRemainder(2, 3)
_, d := divAndRemainder(2, 3)
Vous pouvez nommer les paramètres de retour et les “remplir” dans la fonction. Il faut simplement ajouter return
sans rien pour qu’il renvoie le retour sans y toucher :
func divAndRemainder(a, b) (div, remainder int) {
div = a / b
remainder = a % b
return
}
d, r := divAndRemainder(2, 3)
d, _ := divAndRemainder(2, 3)
_, d := divAndRemainder(2, 3)
Fonctions en tant que variable
Exemple direct :
func myFunc() {
f := func(a int) int {
return a + 1
}
fmt.Println(f(1))
}
Fonctions en tant que paramètres
Exemple direct d’un paramètre qui doit être “une fonction qui prend un entier en tant que paramètre et renvoie un entier” :
func myFunc(a int, f func(int) int) {
fmt.Println(f(a))
}
Tableaux
Base : var a [2]int
fmt.Println("Array a", a, len(a))
Mieux : slice var a []int
La différence entre slice et array ? On ne précise pas le nombre d’éléments.
Pointeurs
Très proche du C. Un exemple direct suffit :
var p *int
i := 4 // int declaration
p = &i // assign the address of the variable to the pointer
*p = 45 // change the value of the variable i
fmt.Println(p, *p) // prints address then value
Switch / case
C’est l’inverse du C : les break
sont implicites, et si on veut vraiment continuer sur le case
suivant, il faut utiliser le mot-clé fallthrough
:
switch i := myfunc(); {
case i < 0:
fmt.Println("negative")
fallthrough
case i == 0:
fmt.Println("zero")
default:
fmt.Println("positive")
}
Conversions
Bizzareries
Pointeurs et structures
Vous pouvez déclarer une structure, et la créer dynamiquement, puis créer un pointeur vers elle. En C, quand on utilise les pointeurs, l’indirection pour accéder aux membres est "->"
, donc on ne peut pas se tromper. Ici, on utilise la même syntaxe, que ce soit avec une structure, directement, ou avec un pointeur, donc indirectement. Exemple concret :
type People struct {
name string
height int
}
var value People
value.name = "Olivier"
value.height = 190
ptr := &value
ptr.name = "Thibault"
ptr.height = 185
Donc on écrit value.name
et ptr.name
alors que l’un est une struct
et l’autre un pointeur. Je n’aime pas du tout cela, cela prête clairement à confusion.