Break, ce casse-tête : comment Go a bouleversé la « règle du switch » habituelle
\n\nSi vous avez déjà codé en C, C++, Java ou JavaScript, vous connaissez le rituel : après chaque case dans un switch, il faut impérativement ajouter un break. Sinon, bienvenue en enfer du « fall-through », où le code s'exécute d'un case à l'autre jusqu'à rencontrer un break ou la fin de la structure.
Imaginez maintenant : vous passez à Go, vous écrivez un switch et, par habitude, vous insérez un break à la fin de chaque case. Le code fonctionne. Mais vous vous demandez : « Est-ce vraiment nécessaire ? Et que se passe-t-il si je l'enlève ? »
Cette question est l'une des plus populaires sur Stack Overflow dans la section Go. Et la réponse surprend les débutants : en Go, le break dans switch et select n'est pas obligatoire, mais il existe et fait quelque chose de différent. Décortiquons cela avec des exemples pour que vous ne soyez plus jamais perdu.
\n\nGo vs. C : un switch « inversé »
\n\nDans les langages classiques de type C, le switch fonctionne ainsi :
// Pseudo-code C\nint x = 2;\nswitch(x) {\n case 1:\n printf("Un");\n break; // Sans break, on passe au case suivant\n case 2:\n printf("Deux");\n break;\n default:\n printf("Autre");\n}\n// Sortie : "Deux"\n\nRetirez le break après case 1 et le programme affichera « UnDeux ». Ce comportement s'appelle le fall-through, et il est souvent source de bugs.
En Go, ils ont décidé : « Assez de ça ! » Par défaut, chaque case dans un switch se termine automatiquement, et break n'est pas nécessaire :
package main\n\nimport "fmt"\n\nfunc main() {\n x := 2\n switch x {\n case 1:\n fmt.Println("Un")\n // break inutile — on sort du switch\n case 2:\n fmt.Println("Deux")\n // break inutile\n default:\n fmt.Println("Autre")\n }\n // Sortie : "Deux"\n}\n\nMais si vous mettez quand même un break, rien de grave : le code quitte simplement le switch plus tôt. Cependant, pourquoi ajouter un break superflu alors que c'est le comportement par défaut ?
Et le fall-through alors ?
\n\nSi vous avez besoin de « tomber » dans le case suivant, Go propose un mot-clé explicite : fallthrough :
switch x {\ncase 1:\n fmt.Println("Un")\n fallthrough // On dit clairement : « Je veux passer au case suivant »\ncase 2:\n fmt.Println("Deux")\ndefault:\n fmt.Println("Autre")\n}\n// Avec x=1, affichera : "Un" et "Deux"\n\nNotez que fallthrough ne fonctionne que pour le case suivant et non en chaîne. Cela a été conçu spécifiquement pour éviter les erreurs accidentelles.
Select : le « frère » multicanal de switch
\n\nGo possède une structure unique : select. Elle ressemble à switch, mais ne fonctionne qu'avec les canaux. Et ici aussi, break existe, mais avec une subtilité.
package main\n\nimport (\n "fmt"\n "time"\n)\n\nfunc main() {\n ch1 := make(chan string)\n ch2 := make(chan string)\n\n go func() {\n time.Sleep(1 * time.Second)\n ch1 <- "Bonjour du canal 1"\n }()\n go func() {\n time.Sleep(2 * time.Second)\n ch2 <- "Bonjour du canal 2"\n }()\n\n select {\n case msg1 := <-ch1:\n fmt.Println(msg1)\n break // Sortie du select\n case msg2 := <-ch2:\n fmt.Println(msg2)\n break // Sortie du select\n case <-time.After(3 * time.Second):\n fmt.Println("Timeout")\n }\n}\n\nIci, break n'est pas non plus obligatoire — le select se termine après l'exécution d'un seul case. Mais à quoi sert-il alors ? La réponse : à sortir d'une boucle externe !