Aller au contenu
English
Compte : non connecté, synchronisation possible Mon apprentissage
Selectionner le thème
English

Tutoriel Golang : apprendre le langage Go (débutant)

  • 60 min

Par mis à jour le

Améliorer cette page

Go

Go, aussi appelé Golang, est un langage de programmation compilé, statiquement typé et open source créé par Google. Il combine une syntaxe minimaliste, une compilation directe en binaire autonome et une gestion native de la concurrence. Ces trois choix expliquent son adoption pour les services réseau et les outils d'infrastructure. Là où Python mise sur la flexibilité et un vaste écosystème, Go mise sur la rapidité d'exécution et la simplicité du code concurrent. Ce guide vous fait écrire vos premiers programmes Go, des variables aux boucles, avec des exemples exécutables.

Dans ce guide, on va apprendre les bases pour que vous puissiez écrire vos premiers scripts Go en un rien de temps.

Le langage Go a été conçu chez Google pour développer des systèmes et des logiciels à grande échelle. Sa création remonte à 2007, sous l'impulsion de trois ingénieurs, Robert Griesemer, Rob Pike et Ken Thompson. Leur objectif : corriger les défauts des langages existants en matière de performance, d'évolutivité et de facilité de maintenance.

Go s'inspire de C et C++ pour la performance, mais ajoute une gestion moderne de la concurrence et supprime une partie de leur complexité. Le langage est dévoilé publiquement en novembre 2009 comme projet open source, et la version 1.0, qui fige une API stable et garantit la compatibilité ascendante, sort en mars 2012. Depuis, chaque version mineure conserve cette promesse de compatibilité, ce qui rassure les entreprises qui misent sur Go pour du code de long terme.

Aujourd'hui, Go équipe des logiciels d'infrastructure de référence : Kubernetes, Docker, Terraform et Prometheus sont écrits en Go. Un écosystème solide s'est construit autour du langage, porté par une communauté qui produit bibliothèques, outils et frameworks. Ses atouts pour ces projets sont constants : binaire autonome facile à distribuer, exécution rapide et concurrence simple à mettre en oeuvre.

  1. Téléchargez l'installateur ou l'archive Rendez-vous sur la page officielle de téléchargement de Go et choisissez la version correspondant à votre système d’exploitation.

  2. Installez Go sur votre système

    • Windows : Téléchargez le fichier .msi, exécutez-le et suivez les étapes de l’assistant d’installation. L’installateur configure automatiquement le chemin d’accès C:\Go\bin.
    • Linux/macOS : Téléchargez l’archive .tar.gz, puis exécutez les commandes suivantes dans le terminal :
Fenêtre de terminal
sudo tar -C /usr/local -xzf go1.xx.x.linux-amd64.tar.gz

(Remplacez go1.xx.x.linux-amd64.tar.gz par le nom du fichier téléchargé.)

  1. Les variables d'environnement importantes

Pour que Go fonctionne correctement, il est essentiel de configurer certaines variables d’environnement. Voici les plus importantes :

  • GOPATH : Indique le répertoire où sont stockés vos projets et dépendances. Par défaut, il est défini dans votre répertoire utilisateur ($HOME/go sur Linux/macOS ou %USERPROFILE%\go sur Windows). Si vous souhaitez personnaliser ce chemin, ajoutez dans votre fichier de configuration shell (~/.bashrc, ~/.zshrc, ou autre) :

    Fenêtre de terminal
    export GOPATH=$HOME/my-go-projects
  • GOROOT : Indique où Go est installé. En général, vous n’avez pas besoin de modifier cette variable, car elle est automatiquement définie après l’installation. Par exemple, sur Linux/macOS, elle est définie à /usr/local/go.

  • PATH : Ajoutez le chemin du dossier contenant les binaires de Go pour pouvoir utiliser les commandes comme go build ou go run. Par exemple :

    Fenêtre de terminal
    export PATH=$PATH:/usr/local/go/bin:$GOPATH/bin

Maintenant que vous avez installé Go, vous pouvez créer votre première application Go.

Pour créer un projet Go, vous devez créer un répertoire dans lequel vous stockerez vos fichiers de code. Par exemple, si vous souhaitez créer un projet nommé my-first-go-project, vous pouvez créer un dossier de ce nom dans votre répertoire utilisateur.

Vous pouvez créer un fichier Go avec n'importe quel éditeur de texte. Par exemple, avec Visual Studio Code, créez un fichier nommé main.go dans le répertoire my-first-go-project.

Dans votre fichier main.go, ajoutez le code suivant :

package main
import "fmt"
func main() {
fmt.Println("Hello, world!")
}

Tout commence par une déclaration de package. En Go, chaque fichier appartient à un package, un regroupement logique du code. Si votre programme doit s’exécuter (et non juste fournir une bibliothèque), il doit obligatoirement appartenir au package main. C’est le point d’entrée reconnu par le compilateur.

Vous avez le squelette (main), il faut maintenant lui ajouter des fonctionnalités. C’est le rôle des packages. Go fournit une bibliothèque standard riche qui vous évite de tout réécrire. Par exemple, pour afficher un message dans le terminal, vous importez le package fmt :

import "fmt"

Sans cette bibliothèque, vous devriez écrire vous-même le code d’affichage. En Go, la fonction Println du package fmt s’en charge.

Si votre programme a besoin de plusieurs packages, regroupez les imports dans un bloc :

import (
"fmt"
"os"
)

Regrouper les imports dans un seul bloc est la convention Go ; l’outil gofmt réordonne et formate ce bloc automatiquement.

La fonction main est le point d’entrée de tout programme Go exécutable. C’est la première fonction appelée au lancement ; sans elle, le programme ne compile pas en exécutable. Voici un exemple simple :

func main() {
fmt.Println("Hello, Go!")
}

Ce code affiche "Hello, Go!" dans le terminal. Il est minimaliste, mais l’exécution démarre bien à partir de cette fonction.

Complexifions un peu. Supposons que vous vouliez demander le nom de l’utilisateur et afficher un message personnalisé :

func main() {
var name string
fmt.Print("Entrez votre nom : ")
fmt.Scanln(&name)
fmt.Printf("Bonjour, %s ! Bienvenue dans Go.\n", name)
}

Ce code reste court et lisible tout en gérant une entrée utilisateur avec fmt.Scanln, le tout dans le package main.

Au fur et à mesure que votre code grandit, il devient essentiel de l’organiser en plusieurs fichiers ou packages. Concentrer tout le code dans un seul fichier rend la maintenance difficile et la réutilisation impossible dès que le programme dépasse quelques dizaines de lignes.

Voici un exemple d’organisation typique :

  • Dossier du projet :

    myproject/
    ├── main.go
    ├── utils/
    └── helper.go

Dans main.go, vous écrivez le code principal :

package main
import (
"fmt"
"myproject/utils" // Import d’un package local
)
func main() {
message := utils.GetGreeting("Go")
fmt.Println(message)
}

Et dans utils/helper.go, vous placez une fonction utilitaire :

package utils
func GetGreeting(name string) string {
return "Bonjour, " + name + " !"
}

Avec cette structure, votre code est propre, modulaire et facile à maintenir.

Go repose sur un système de typage statique. Cela signifie que chaque variable doit avoir un type défini lors de sa déclaration et que, une fois le type attribué, il ne peut pas être modifié.

Ce principe assure une conformité stricte lors de l'exécution et réduit les erreurs liées à l'utilisation incorrecte des variables. Les développeurs écrivent du code plus sûr et bénéficient d'optimisations de performance offertes par cette vérification anticipée des types.

Tout commence avec les types simples, la base de tout programme. Ces types permettent de manipuler des nombres, du texte ou des booléens. Mais Go, fidèle à sa philosophie, ne laisse rien au hasard.

Go propose différentes tailles pour les entiers afin de répondre à des besoins spécifiques :

  • int : La taille dépend de votre architecture (32 ou 64 bits).
  • int8, int16, int32, int64 : Des tailles fixes.

Exemple :

var age int = 30
year := 2024 // Déclaration courte

Ce code illustre comment déclarer et attribuer des valeurs à des variables de type int en Go. On utilise ici deux méthodes :

  • la déclaration explicite avec le mot-clé 'var' où le type est spécifié
  • et la déclaration courte avec ':=' qui infère le type de la valeur assignée.

Idéal pour les calculs nécessitant des décimales. Go propose deux tailles :

  • float32
  • float64 (ce dernier étant plus précis).

Exemple :

var temperature float64 = 37.5
pi := 3.14159

Les booléens sont simples et directs : true ou false. Ils sont souvent utilisés dans les conditions.

Exemple :

var isRunning bool = true
completed := false

Les chaînes de caractères sont des types de données très utiles. Elles représentent du texte : des noms de fichiers, des adresses, des adresses IP, etc. Une string Go est immuable : on ne modifie pas un caractère en place.

Exemple :

var name string = "Alice"
greeting := "Hello, Go!"

Pour gérer des collections ou modéliser des entités complexes, Go propose des types composites, chacun conçu pour un usage spécifique.

Taille fixe, parfait pour des données dont la taille est connue à l’avance.

Exemple :

var numbers [5]int = [5]int{1, 2, 3, 4, 5}

Une version plus flexible des tableaux, capable de croître ou rétrécir dynamiquement. C’est l’un des types les plus utilisés en Go.

Exemple :

numbers := []int{1, 2, 3, 4}
numbers = append(numbers, 5) // Ajoute un élément

Go offre une structure clé-valeur appelée map, idéale pour organiser des données par association.

Exemple :

capitals := map[string]string{
"France": "Paris",
"Italie": "Rome",
}
capitals["Allemagne"] = "Berlin"

Permettent de regrouper plusieurs types dans une entité personnalisée, idéale pour modéliser des objets réels.

Exemple :

type Person struct {
Name string
Age int
}
person := Person{Name: "Alice", Age: 30}

Go impose une conversion explicite entre les types, ce qui garantit un contrôle strict sur les transformations de données. Cette approche réduit les erreurs potentielles, puisque chaque conversion est intentionnelle et vérifiée par le programmeur.

Pour passer d'un type entier (int) à un type flottant (float64), vous devez explicitement convertir le type :

var x int = 42
var y float64 = float64(x)

Autre exemple :

var x int = 123
var s string = fmt.Sprintf("%d", x)

Ces conversions évitent les erreurs subtiles et rendent le comportement du code plus prévisible.

Les opérateurs en Go sont conçus pour être simples et intuitifs. Leur utilisation directe s’inscrit dans l’esprit du langage, qui privilégie la lisibilité et la robustesse. Calculs, comparaisons ou manipulations avancées : ils couvrent une large gamme de besoins tout en restant faciles à comprendre.

Ces opérateurs permettent d’effectuer des calculs mathématiques de base.

OpérateurDescriptionExemple
+Additionx + y
-Soustractionx - y
*Multiplicationx * y
/Divisionx / y
%Modulo (reste de division)x % y

Exemple :

a := 10
b := 3
fmt.Println("Addition :", a+b) // 13
fmt.Println("Division :", a/b) // 3 (division entière)
fmt.Println("Modulo :", a%b) // 1

Attention : les opérateurs comme / fonctionnent en division entière si les variables sont des entiers (int). Pour une division décimale, utilisez des types float64.

Les opérateurs relationnels permettent de comparer deux valeurs. Ils retournent toujours un résultat de type bool (true ou false).

OpérateurDescriptionExemple
==Égal àx == y
!=Différent dex != y
<Inférieur àx < y
<=Inférieur ou égal àx <= y
>Supérieur àx > y
>=Supérieur ou égal àx >= y

Exemple :

x := 5
y := 10
fmt.Println("x == y :", x == y) // false
fmt.Println("x < y :", x < y) // true

Les opérateurs logiques sont utilisés pour combiner ou inverser des expressions conditionnelles.

OpérateurDescriptionExemple
&&ET logiquex > 0 && y > 0
||OU logiquex > 0 || y > 0
!NON logique (inversion)!true

Exemple :

a := 5
b := 10
fmt.Println("a > 0 && b > 0 :", a > 0 && b > 0) // true
fmt.Println("a < 0 || b > 0 :", a < 0 || b > 0) // true
fmt.Println("!(a > b) :", !(a > b)) // true

Les opérateurs d'affectation servent à attribuer ou modifier la valeur d’une variable.

OpérateurDescriptionExemple
=Affectationx = y
+=Ajout et affectationx += y
-=Soustraction et affectationx -= y
*=Multiplication et affectationx *= y
/=Division et affectationx /= y
%=Modulo et affectationx %= y

Exemple :

x := 10
x += 5 // x = x + 5
fmt.Println(x) // 15
x *= 2 // x = x * 2
fmt.Println(x) // 30

Les opérateurs bit-à-bit permettent de manipuler directement les bits des nombres. Ils servent dans des cas spécifiques, comme le traitement de données binaires ou les masques de drapeaux.

OpérateurDescriptionExemple
&ET bit-à-bitx & y
|OU bit-à-bitx | y
^OU exclusif (XOR)x ^ y
&^AND NOT (effacement de bits)x &^ y
<<Décalage à gauchex << 1
>>Décalage à droitex >> 1

Exemple :

a := 6 // 110 en binaire
b := 3 // 011 en binaire
fmt.Println("a & b :", a & b) // 2 (010 en binaire)
fmt.Println("a | b :", a | b) // 7 (111 en binaire)
fmt.Println("a ^ b :", a ^ b) // 5 (101 en binaire)

Exercice pratique : Calcul simple avec des opérateurs

Section intitulée « Exercice pratique : Calcul simple avec des opérateurs »

Écrivons un petit programme qui utilise plusieurs opérateurs pour effectuer des calculs simples basés sur des entrées utilisateur.

package main
import (
"fmt"
)
func main() {
var a, b int
fmt.Print("Entrez le premier nombre : ")
fmt.Scanln(&a)
fmt.Print("Entrez le deuxième nombre : ")
fmt.Scanln(&b)
fmt.Println("Addition :", a+b)
fmt.Println("Soustraction :", a-b)
fmt.Println("Multiplication :", a*b)
if b != 0 {
fmt.Println("Division :", a/b)
} else {
fmt.Println("Division par zéro impossible")
}
fmt.Println("Modulo :", a%b)
}

Les structures de contrôle en Go gèrent le flux d'exécution de votre programme en fonction de conditions ou d'itérations. Simples mais puissantes, elles s’intègrent à la philosophie minimaliste du langage. Voici une introduction pratique à ces structures essentielles.

Go utilise des conditions pour exécuter du code selon des critères. La syntaxe ressemble à celle d'autres langages, mais sans parenthèses autour de la condition (même si elles sont autorisées). Le if accepte else if et else pour enchaîner plusieurs cas.

Exemple simple :

age := 18
if age >= 18 {
fmt.Println("Vous êtes majeur.")
} else {
fmt.Println("Vous êtes mineur.")
}

Avec plusieurs cas :

score := 85
if score >= 90 {
fmt.Println("Excellent")
} else if score >= 75 {
fmt.Println("Bien")
} else {
fmt.Println("À améliorer")
}

Le switch en Go est une alternative élégante aux longues chaînes de if-else. Il est simple à utiliser et puissant grâce à des fonctionnalités avancées, comme les cas multiples sur une même ligne.

  • Exemple de base :

    day := "mardi"
    switch day {
    case "lundi":
    fmt.Println("Début de la semaine")
    case "mardi", "mercredi":
    fmt.Println("Milieu de semaine")
    case "jeudi", "vendredi":
    fmt.Println("Presque le week-end")
    default:
    fmt.Println("C'est le week-end !")
    }
  • Switch sans expression : Lorsque vous omettez l'expression du switch, chaque case agit comme une condition indépendante :

    num := 7
    switch {
    case num%2 == 0:
    fmt.Println("Nombre pair")
    case num%2 != 0:
    fmt.Println("Nombre impair")
    }

Contrairement à d'autres langages, les blocs case n’ont pas besoin de break : l'exécution s'arrête automatiquement après chaque bloc.

Go simplifie la gestion des boucles avec une unique structure, la boucle for. Elle peut remplacer des constructions comme while ou do-while présentes dans d'autres langages.

  • Boucle classique :

    for i := 0; i < 5; i++ {
    fmt.Println("Itération :", i)
    }
  • Boucle while simulée : En Go, une boucle for sans initialisation ni incrémentation agit comme un while.

    i := 0
    for i < 5 {
    fmt.Println("i vaut :", i)
    i++
    }
  • Boucle infinie : Une boucle infinie est déclarée avec un for sans condition.

    for {
    fmt.Println("Boucle infinie")
    break // Nécessite une condition pour sortir
    }

Contrôler le flux dans les boucles : break, continue et goto

Section intitulée « Contrôler le flux dans les boucles : break, continue et goto »

Go offre des mots-clés pour manipuler le comportement des boucles.

  • Sortir d’une boucle : break

    for i := 0; i < 10; i++ {
    if i == 5 {
    break
    }
    fmt.Println(i)
    }
  • Passer à l’itération suivante : continue

for i := 0; i < 10; i++ {
if i%2 == 0 {
continue
}
fmt.Println(i) // Affiche uniquement les nombres impairs
}
  • Sauter à un label : goto

    i := 0
    for {
    if i == 5 {
    goto End
    }
    i++
    }
    End:
    fmt.Println("Boucle terminée.")

goto est à utilisé dans les cas où il est impossible d'utiliser break ou continue.

Voici la version en Go du jeu de devinette, adaptée pour respecter la logique de Go tout en reprenant l'exercice Python. Go convient bien à ce type d’exercice grâce à sa simplicité et à sa performance.

L'objectif de ce programme est de créer un jeu de devinette où l'utilisateur tente de trouver un nombre mystère choisi à l'avance par le programme. Le but est de maîtriser les bases de Go : les boucles, les conditions et l’interaction utilisateur.

Ce que doit contenir le programme :

  1. Un nombre à deviner : Un nombre fixe (par exemple, 42) que l'utilisateur doit deviner.
  2. Des messages d'accueil : Des instructions pour expliquer à l'utilisateur comment jouer.
  3. Un compteur d'essais : Une variable qui compte les tentatives.
  4. Une boucle de jeu : Une boucle qui continue jusqu'à ce que le nombre mystère soit trouvé.
  5. Des comparaisons : Des indices (plus grand ou plus petit) pour guider l’utilisateur.
  6. Un message de victoire : Un message pour féliciter l’utilisateur avec le nombre d’essais utilisés.

Cette page pose les bases ; le parcours complet va des fondamentaux jusqu'à la mise en production, en cinq volets qui s'enchaînent dans cet ordre. Le fil rouge : écrire du Go idiomatique et testé, avec les mêmes briques que celles qu'on retrouve dans de vrais outils (CLI, sortie terminal, clients d'API, bibliothèques réutilisables). Les sujets déjà disponibles sont liés ci-dessous ; ceux marqués à venir arrivent progressivement.

Le socle indispensable : manipuler les données, structurer le code et gérer les erreurs proprement. Il commence par écrire des fonctions (paramètres, retours multiples, variadiques, closures et génériques), puis modélise des entités avec les structures, leurs méthodes et leur composition. Les slices, maps et tableaux couvrent les collections du quotidien, avec leurs pièges de partage de mémoire.

Les pointeurs expliquent quand passer une valeur ou une référence, ce qui prépare les méthodes et récepteurs : attacher un comportement à un type, avec un récepteur valeur ou pointeur. Les interfaces forment le cœur du design Go : on découple par le comportement, pas par le type. La gestion des erreurs (error, fmt.Errorf avec %w, errors.Is et errors.As, erreurs sentinelles) et les packages et modules (go mod, convention internal/, visibilité) terminent le volet.

C'est ce qui fait la réputation de Go : exécuter en parallèle sans se tirer une balle dans le pied. Le volet part des goroutines et channels pour lancer des tâches concurrentes et les faire communiquer, puis détaille les channels : rendez-vous, buffer, fermeture, select et motifs concrets (pipeline, fan-in, sémaphore).

La leçon sync, WaitGroup et errgroup apprend à attendre des tâches, à protéger un état partagé avec un Mutex et à propager la première erreur. Le contexte (context.Context) gère annulation, délais et propagation avec ctx.Done(), WithTimeout et context.Value : il est indispensable aux clients d'API du volet 4.

Du code qu'on livre en confiance : testé, vérifié, versionné. Le volet enseigne la forme de test idiomatique en Go (table-driven, go test -cover, mocks par interface), puis la qualité du code : formater, détecter les bugs mécaniques avec go vet, staticcheck et golangci-lint, en local et en CI. Il se termine par compiler et versionner un binaire : go build, injection de version via -ldflags -X, réduction de taille et cross-compilation.

Les briques concrètes pour écrire des outils comme en production. La première est une CLI avec Cobra : commande racine, sous-commandes, flags persistants et locaux, aide générée. Viennent ensuite la configuration YAML et TOML, chargée dans des structures via les struct tags avec valeurs par défaut, validation et surcharge par drapeaux, puis la leçon pour consommer une API REST : net/http authentifié, décodage JSON, pagination et contexte, avec le client généré go-github.

Trois sujets de ce volet sont à venir : un terminal stylé avec Lipgloss (sortie lisible et colorée, avec détection du terminal), la conception d'une bibliothèque réutilisable (API publique propre, stable et testée, façon module partagé) et une architecture par interfaces (composants enfichables, collectors ou moteurs, découplés par interface).

Livrer, superviser et sécuriser l'outil. Le logging structuré avec slog produit des logs JSON avec niveaux, attributs et logger contextuel, sans dépendance. La leçon sécurité supply chain détecte les failles atteignables avec govulncheck, garantit l'intégrité du go.sum et génère un SBOM. Un sujet reste à venir : packaging, Docker et CI, avec une image minimale (distroless), un build reproductible et un pipeline.

Ces réponses courtes traitent les questions qui reviennent le plus avant d'apprendre Go : sa définition, son coût, l'installation, la compilation, et les comparaisons avec Python et Rust pour choisir le bon langage.

Vous maîtrisez maintenant les bases de Go et vous êtes prêt à écrire vos premières applications. Le parcours ci-dessus vous mène pas à pas vers du code de production : concurrence, tests, CLI, clients d'API et bibliothèques réutilisables.

Ce projet vous est utile ?

Les guides, formations, quiz et labs restent gratuits. Si vous les utilisez régulièrement, vous pouvez contribuer à leur maintenance et à leur développement.

Devenir membre de soutien (nouvel onglet) Soutenir une fois (nouvel onglet) En savoir plus

Suivez aussi le projet sur LinkedIn