ProgrammationDéveloppeur Backend

Décrivez les spécificités de la manipulation des slices en Go : qu'est-ce qu'un nil slice, quelle est la différence entre length et capacity, et comment augmenter correctement un slice sans fuite de données ou panique ?

Réussissez les entretiens avec l'assistant IA Hintsage

Réponse.

Un slice est un tableau dynamique, l'unité structurale principale lors de la manipulation de tableaux en Go. Historiquement, les langages de programmation proposaient des tableaux fixes ou des structures plus lourdes. Go a implémenté les slices comme un outil pratique pour gérer des collections de mémoire avec une gestion automatique de leur taille et la possibilité de modifier leur longueur.

Le problème réside dans la gestion correcte de la mémoire, le traitement des cas extrêmes (vides, nil, slices pleins), ainsi que la compréhension de la différence entre la longueur et la capacité d'un slice.

La solution consiste à utiliser correctement les fonctions intégrées len(), cap(), et à manipuler les slices selon les conventions de Go.

Exemple de code :

var a []int // nil slice, len=0, cap=0 b := make([]int, 0) // slice vide, len=0, cap=0 c := make([]int, 3, 5) // len=3, cap=5 c = append(c, 4, 5, 6) // cap augmentera automatiquement

Caractéristiques clés :

  • Le nil slice (var s []int) n'alloue pas de mémoire du tout, il se distingue d'un slice vide (make([]int, 0)) uniquement en interne.
  • La longueur montre le nombre actuel d'éléments, la capacité — le maximum sans allocation supplémentaire.
  • Lors de l'append, si la capacité est insuffisante, un nouveau est créé en coulisses, tandis que les anciennes données restent inchangées.

Questions pièges.

Quelle sera la longueur et la capacité d'un slice après append à un nil slice ?

Le nil slice (var s []int) après append(s, 1) devient un slice de longueur 1, de capacité 1 — Go alloue l'espace automatiquement.

var s []int s = append(s, 42) // s est maintenant [42], len=1, cap=1

Peut-on accéder à la capacité d'un slice égal à nil ?

Oui, pour un nil slice, les deux fonctions — len et cap — retournent 0. Il n’y aura pas de panique.

var s []int fmt.Println(len(s), cap(s)) // 0 0

Que se passe-t-il si on essaie d'assigner un élément par index sans allocation préalable de mémoire à un slice égal à nil ?

Panique index out of range, car le slice n’a pas d’éléments.

var s []int s[0] = 1 // panic: erreur d'exécution : index out of range

Erreurs typiques et anti-patterns

  • Erreurs lors du passage d'un nil slice ou d'un slice vide à une fonction où une certaine longueur est requise.
  • Surcharge d'un slice sans prendre en compte la croissance de la capacité et boucles mal écrites avec append.
  • Tentatives d'assignation par index au lieu de append pour ajouter des éléments.

Exemple de la vie réelle

Cas négatif

L'équipe a décidé dans le serveur Go d'utiliser partout uniquement var s []T, s'attendant à ce que cela soit toujours équivalent à make([]T, 0). En conséquence, certaines marshalisations JSON retournaient null au lieu de [].

Avantages :

  • Moins d'allocations de mémoire au démarrage.

Inconvénients :

  • Fonctionnement incorrect de JSON (en conséquence, null au lieu d'un tableau en arrivant).
  • Erreurs d'exécution lors de l'accès par index.

Cas positif

Utiliser make([]T, 0, 100) pour la préallocation, et ensuite — uniquement append dans une boucle. Cela minimise les allocations mémoire et améliore souvent les performances.

Avantages :

  • Manipulation efficace de la mémoire.
  • Pas de panique et valeurs inattendues lors de la marshaliсation.

Inconvénients :

  • Risque de surconsommation mémoire si le nombre d'éléments attendu ne correspond pas à la capacité donnée.