// Go

Apprendre Go (Golang) : premiers pas

Apprendre Go, souvent appelé Golang, c’est miser sur un langage conçu pour la simplicité et la performance à l’échelle. Créé chez Google pour répondre aux besoins de gros systèmes, Go se distingue par une syntaxe minimaliste, une compilation rapide vers un binaire autonome et un modèle de concurrence remarquablement élégant. Ce guide vous emmène de l’installation aux fondamentaux, jusqu’aux goroutines et aux cas d’usage réels — backend et outils en ligne de commande.

Pourquoi choisir Go ?

Go a été pensé pour résoudre des problèmes concrets de développement à grande échelle : temps de compilation longs, complexité du code, difficulté à écrire du parallélisme sûr. Ses partis pris sont assumés :

  • Simplicité volontaire : peu de mots-clés, une seule façon de faire les choses. On lit du code Go écrit par autrui sans effort.
  • Compilation en binaire unique : Go produit un exécutable autonome, sans dépendances à installer sur la machine cible. Le déploiement en devient trivial.
  • Concurrence native : les goroutines et les canaux rendent la programmation parallèle accessible.

Ces choix font de Go un favori pour les services web, les microservices, les outils DevOps (Docker et Kubernetes sont écrits en Go) et les CLI. Le langage sacrifie volontairement certaines fonctionnalités avancées au profit de la lisibilité. Ce minimalisme déroute parfois, mais il accélère le travail en équipe.

Installer Go

Rendez-vous sur go.dev, téléchargez l’installeur pour votre système (Windows, macOS ou Linux) et suivez les instructions. Vérifiez ensuite l’installation dans un terminal :

go version

Go s’accompagne d’un outillage intégré exemplaire : compilation, tests, formatage et gestion de dépendances passent tous par la commande go. Côté éditeur, VS Code avec l’extension Go officielle configure automatiquement l’analyse et l’autocomplétion. Un atout appréciable : gofmt formate le code selon un standard unique, ce qui met fin aux débats de style.

Votre premier programme

Créez un dossier de projet, puis initialisez un module (nous y reviendrons) et un fichier main.go :

package main

import "fmt"

func main() {
    nom := "Coder Studio"
    fmt.Printf("Bonjour, %s !\n", nom)
}

Exécutez-le directement :

go run main.go

Plusieurs points à retenir. Tout fichier appartient à un package, et main est celui d’un programme exécutable. L’import charge des paquets, ici fmt pour l’affichage. L’opérateur := déclare une variable avec inférence de type : Go devine que nom est une chaîne. C’est la forme la plus courante pour déclarer une variable locale.

Types, variables et structures

Go est statiquement typé, mais l’inférence allège l’écriture. Les types de base sont classiques :

var age int = 30
var prix float64 = 19.90
var actif bool = true
var nom string = "Léa"

// Forme courte, avec inférence
ville := "Nantes"

Pour les collections, Go propose les slices (listes dynamiques) et les maps (dictionnaires clé-valeur) :

courses := []string{"pain", "lait"}
courses = append(courses, "œufs")

profil := map[string]int{"Léa": 28, "Tom": 34}

for cle, valeur := range profil {
    fmt.Printf("%s a %d ans\n", cle, valeur)
}

Pour modéliser des objets du monde réel, on utilise les structs, associées à des méthodes. Go ne possède pas de classes : il combine structs et interfaces pour organiser le code.

type Article struct {
    Titre  string
    Auteur string
}

func (a Article) Resume() string {
    return a.Titre + " — par " + a.Auteur
}

func main() {
    a := Article{Titre: "Débuter en Go", Auteur: "Léa"}
    fmt.Println(a.Resume())
}

La gestion des erreurs à la façon de Go

Go n’utilise pas d’exceptions. Une fonction qui peut échouer retourne une valeur d’erreur en dernier résultat, que l’appelant doit vérifier explicitement :

import (
    "fmt"
    "strconv"
)

func main() {
    n, err := strconv.Atoi("42")
    if err != nil {
        fmt.Println("Conversion impossible :", err)
        return
    }
    fmt.Println("Nombre :", n)
}

Ce motif if err != nil est omniprésent en Go. Il est verbeux, mais il rend chaque point de défaillance visible dans le flux du code — impossible d’ignorer une erreur par distraction.

Bonne pratique — Ne jamais ignorer une erreur Le compilateur autorise à ignorer une erreur avec _, mais c’est rarement une bonne idée. Traitez chaque err : loggez-la, propagez-la ou gérez-la. La robustesse d’un service Go tient en grande partie à cette discipline.

Goroutines et concurrence

C’est la fonctionnalité signature de Go. Une goroutine est une fonction exécutée de façon concurrente, avec un coût mémoire minime : on peut en lancer des milliers. Il suffit du mot-clé go :

import (
    "fmt"
    "time"
)

func saluer(nom string) {
    fmt.Println("Bonjour", nom)
}

func main() {
    go saluer("Léa")
    go saluer("Tom")
    time.Sleep(time.Millisecond * 100) // laisser le temps aux goroutines
}

Pour coordonner des goroutines et échanger des données sans risque, Go fournit les channels (canaux). Un canal transmet des valeurs d’une goroutine à une autre de façon sûre :

func main() {
    resultats := make(chan int)

    go func() {
        resultats <- 2 + 3 // envoie dans le canal
    }()

    valeur := <-resultats // reçoit du canal
    fmt.Println("Résultat :", valeur)
}

La philosophie de Go tient dans une formule connue : « ne communiquez pas en partageant la mémoire, partagez la mémoire en communiquant ». Autrement dit, on privilégie les canaux plutôt que les verrous manuels pour synchroniser les tâches. C’est ce qui rend la concurrence en Go à la fois puissante et abordable.

Bonne pratique — Une goroutine doit avoir une fin prévue Lancer une goroutine est facile ; s’assurer qu’elle se termine l’est moins. Une goroutine oubliée qui attend indéfiniment est une fuite. Utilisez les canaux ou le paquet sync pour maîtriser leur cycle de vie.

Les modules : gérer les dépendances

Depuis plusieurs versions, Go organise les projets en modules. On initialise un module au démarrage d’un projet :

go mod init exemple.com/mon-projet

Cela crée un fichier go.mod qui décrit le projet et ses dépendances. Ajouter une bibliothèque externe se fait par un simple import dans le code, suivi de :

go mod tidy

Cette commande télécharge les dépendances manquantes et retire celles qui ne servent plus. La gestion des versions est ainsi reproductible et intégrée, sans outil tiers.

Cas d’usage : où Go excelle

Go n’est pas universel, mais il domine plusieurs terrains où ses qualités font la différence :

  • Backend et microservices : sa bibliothèque standard permet d’écrire un serveur HTTP performant en quelques lignes, sans framework lourd.
  • Outils en ligne de commande : le binaire unique et la compilation croisée facile en font un choix idéal pour distribuer des CLI.
  • Infrastructure et DevOps : de nombreux outils cloud modernes sont écrits en Go, précisément pour ces raisons.

Un serveur web minimal illustre cette économie de moyens :

package main

import (
    "fmt"
    "net/http"
)

func main() {
    http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
        fmt.Fprintln(w, "Bonjour depuis Go !")
    })
    http.ListenAndServe(":8080", nil)
}

En une poignée de lignes, sans dépendance externe, vous avez un serveur fonctionnel. Cette efficacité, combinée à la simplicité de déploiement, explique l’engouement pour Go dans le développement d’API — un sujet que prolonge notre guide des API REST.

Progresser efficacement en Go

Go s’apprend vite, précisément parce qu’il est minimaliste. Pour ancrer les bases : suivez le Tour of Go interactif officiel, lisez du code de la bibliothèque standard (elle est exemplaire), et construisez un vrai petit projet — une CLI ou une mini-API. Adoptez dès le départ les réflexes de la communauté : formater avec gofmt, traiter chaque erreur, et garder les fonctions courtes. Cette culture de la simplicité est au cœur du langage, et c’est elle qui rend le code Go si agréable à maintenir à plusieurs.

À lire ensuite