Comment réussir un entretien Go : les meilleures questions
Go (Golang) est l'un des langages les plus demandés pour créer des applications serveur à forte charge et des microservices. Un entretien pour un poste de développeur Go teste souvent non seulement la connaissance de la syntaxe, mais aussi la compréhension du fonctionnement interne : goroutines, canaux, interfaces et gestion de la mémoire. Dans cet article, nous allons décortiquer le top 10 des questions les plus fréquemment posées lors des entretiens, avec des exemples de code et des explications.
1. Quelle est la différence entre un tableau et une slice (array vs slice) ?
C'est une question classique pour tester la compréhension des bases de Go.
- Tableau (array) — c'est une séquence fixe d'éléments du même type. La taille du tableau fait partie de son type.
- Slice — c'est une structure dynamique qui fait référence à un tableau sous-jacent. Une slice peut grandir et changer de taille.
// Tableau — taille fixevar arr [3]int = [3]int{1, 2, 3}// Slice — dynamiquevar slc []int = []int{1, 2, 3}
// Important : arr et [4]int sont des types différents// Les slices sont passées par référence (pointeur vers le tableau sous-jacent)Conseil : Si vous devez modifier la longueur, utilisez une slice. Si vous avez besoin d'une garantie de taille fixe, utilisez un tableau.
2. Que sont les goroutines et comment fonctionnent-elles ?
Une goroutine est un fil d'exécution léger géré par le runtime de Go. Contrairement aux threads système (OS threads), les goroutines ont une pile plus petite (à partir de 2 Ko) et commutent rapidement.
- Lancement d'une goroutine :
go func() - Les goroutines travaillent dans le même espace d'adressage, donc l'accès aux données partagées doit être synchronisé (via des canaux ou des mutex).
package main
import ( "fmt" "time")
func printNumbers() { for i := 1; i <= 5; i++ { time.Sleep(100 * time.Millisecond) fmt.Println(i) }}
func main() { go printNumbers() // lancement de la goroutine time.Sleep(1 * time.Second) // on attend la fin fmt.Println("Main done")}Important : La fonction principale n'attend pas la fin des goroutines. Pour la synchronisation, utilisez sync.WaitGroup ou des canaux.
3. Comment fonctionnent les canaux (channels) ?
Les canaux sont des "tuyaux" typés par lesquels les goroutines échangent des données. Ils assurent un transfert de données sécurisé sans verrouillage explicite.
- Canal non bufferisé : l'émetteur est bloqué jusqu'à ce que le récepteur lise les données.
- Canal bufferisé : l'émetteur est bloqué uniquement lorsque le buffer est plein.
ch := make(chan int) // non bufferiséchBuf := make(chan int, 3) // bufferisé (capacité 3)
// Envoigo func() { ch <- 42}()
// Réceptionvalue := <-chfmt.Println(value)
// Fermeture du canalclose(ch)// La lecture d'un canal fermé retourne la valeur zéroQuestion fréquente : Que se passe-t-il si on lit depuis un canal nil ? — Réponse : la goroutine se bloque pour toujours (deadlock).
4. Que sont les interfaces en Go et en quoi diffèrent-elles des autres langages ?
Une interface en Go est un ensemble de méthodes. Contrairement à Java ou C#, l'implémentation d'une interface en Go est implicite (duck typing) : un type satisfait automatiquement une interface s'il implémente toutes ses méthodes.
type Speaker interface { Speak() string}
type Dog struct{}func (d Dog) Speak() string { return "Woof!" }
type Cat struct{}func (c Cat) Speak() string { return "Meow!" }
func makeSound(s Speaker) { fmt.Println(s.Speak())}
func main() { makeSound(Dog{}) // Woof! makeSound(Cat{}) // Meow!}Pourquoi c'est important : Cela permet d'écrire un code flexible et faiblement couplé. L'interface vide interface{} (ou any dans Go 1.18+) peut stocker une valeur de n'importe quel type.