Skip to content

Go Langage Cheat Sheet

Go (également connu sous le nom de Golang) est un langage compilé, statiquement typé, développé par Robert Griesemer, Rob Pike et Ken Thompson chez Google. La syntaxe de Go est proche de celle du C, mais il propose : la sécurité mémoire, le GC (Garbage Collection), le typage structurel et la concurrence de style CSP.

Hello world

package main

import "fmt"

func main() {
  message := greetMe("world")
  fmt.Println(message)
}

func greetMe(name string) (string) {
  return "Hello, " + name + "!"
}
$ go build

Variables

Déclaration de variable

var msg string
msg = "Hello"

Sténographie

msg := "Hello"

Constantes

const Phi = 1.618

Les constantes peuvent être des caractères, des chaînes de caractères, des booléens ou des valeurs numériques.

Types de base

Chaînes de caractères (Strings)

str := "Hello"
str := `Multiligne
string`

Le type pour les chaînes est string.

Nombres

Types typiques

num := 3          // int
num := 3.         // float64
num := 3 + 4i     // complex128
num := byte('a')  // byte (alias pour uint8)

Autres types

var u uint = 7        // uint (non signé)
var p float32 = 22.7  // float 32 bits

Pointeurs

func main () {
  b := *getPointer()
  fmt.Println("La valeur est", b)
}
 
func getPointer () (myPointer *int) {
  a := 234
  return &a
}

Les pointeurs pointent vers un emplacement mémoire d’une variable. Go est entièrement géré par un ramasse-miettes (garbage collector).

Tableaux (Arrays)

// var numbers [5]int
numbers := [...]int{0, 0, 0, 0, 0}

La taille des tableaux est fixe.

Slices (Tranches)

slice := []int{2, 3, 4}
slice := []byte("Hello")

Contrairement aux tableaux, les slices ont une taille dynamique.

Contrôle de flux

Conditionnels

if day == "sunday" || day == "saturday" {
  rest()
} else if day == "monday" && isTired() {
  groan()
} else {
  work()
}

Déclaration dans if

if _, err := getResult(); err != nil {
  fmt.Println("Uh oh")
}

Une instruction if peut exécuter une instruction simple avant l’expression conditionnelle.

Switch

switch day {
  case "sunday":
    // les cas n'ont pas de "fallthrough" par défaut !
    fallthrough

  case "saturday":
    rest()

  default:
    work()
}

Fonctions

Lambdas

myfunc := func() bool {
  return x > 10000
}

Les fonctions sont des objets de première classe.

Types de retour multiples

a, b := getMessage()
func getMessage() (a string, b string) {
  return "Hello", "World"
}

Valeurs de retour nommées

func split(sum int) (x, y int) {
  x := sum * 4 / 9
  y := sum - x
  return
}

En nommant les valeurs de retour dans la déclaration, return (sans arguments) renverra les variables portant ces noms.

Paquets (Packages)

Chargement

import "fmt"
import "math/rand"
import (
  "fmt"        // donne fmt.Println
  "math/rand"  // donne rand.Intn
)

Les deux sont identiques.

Alias

import r "math/rand"
 
r.Intn()

Noms exportés

func Hello () {
  ···
}

Les noms exportés commencent par une lettre majuscule.

Paquets

package hello

Chaque fichier de paquet doit commencer par une déclaration package.

Concurrence

Goroutines

func main() {
  // Un "canal" (channel)
  ch := make(chan string)

  // Démarrer des routines concurrentes
  go push("Moe", ch)
  go push("Larry", ch)
  go push("Curly", ch)

  // Lire 3 résultats
  // (Puisque nos goroutines sont concurrentes,
  // l'ordre n'est pas garanti !)
  fmt.Println(<-ch, <-ch, <-ch)
}
 
func push(name string, ch chan string) {
  msg := "Hey, " + name
  ch <- msg
}

Les canaux sont des objets de communication sécurisés pour la concurrence utilisés dans les goroutines.

Canaux tamponnés (Buffered Channels)

ch := make(chan int, 2)
ch <- 1
ch <- 2
ch <- 3
// erreur fatale :
// all goroutines are asleep - deadlock!

Les canaux tamponnés limitent le nombre de messages qu’ils peuvent contenir.

Fermer les canaux

Ferme un canal

ch <- 1
ch <- 2
ch <- 3
close(ch)

Parcourir un canal jusqu’à sa fermeture

for i := range ch {
  ···
}

Fermé si ok == false

v, ok := <- ch

Defer & Panic

Defer

func main() {
  defer fmt.Println("Fait")
  fmt.Println("Travail en cours...")
}

Retarde l’exécution d’une fonction jusqu’à ce que la fonction environnante se termine. Les arguments sont évalués immédiatement, mais l’appel de la fonction n’est exécuté qu’à la fin.

Defer avec Lambdas

func main() {
  defer func() {
    fmt.Println("Fait")
  }()
  fmt.Println("Travail en cours...")
}

Les lambdas sont préférables pour les blocs différés.

Structs (Structures)

Définition

type Vertex struct {
  X int
  Y int
}

func main() {
  v := Vertex{1, 2}
  v.X = 4
  fmt.Println(v.X, v.Y)
}

Littéraux

v := Vertex{X: 1, Y: 2}
// Les noms de champs peuvent être omis
v := Vertex{1, 2}
// Y est implicite
v := Vertex{X: 1}

Vous pouvez également spécifier les noms de champs.

Pointeurs vers des structures

v := &Vertex{1, 2}
v.X = 2

Quand v est un pointeur, v.X et (*v).X sont identiques.

Méthodes

Receveurs (Receivers)

type Vertex struct {
  X, Y float64
}
func (v Vertex) Abs() float64 {
  return math.Sqrt(v.X * v.X + v.Y * v.Y)
}
 
v := Vertex{1, 2}
v.Abs()

Il n’y a pas de classes, mais vous pouvez définir des fonctions sur les types en utilisant des receveurs.

Receveurs de pointeur

func (v *Vertex) Scale(f float64) {
  v.X = v.X * f
  v.Y = v.Y * f
}
 
v := Vertex{6, 12}
v.Scale(0.5)
// `v` est mis à jour