Comparaison de struct, slice et map en Go : analyse complète

Formateur Python en ligne pour débutants

Apprenez Python facilement sans surcharge théorique. Résolvez des tâches pratiques avec vérification automatique et écrivez du code directement dans le navigateur.

Start Course

Comparaison de struct, slice et map en Go : du débutant au pro

\n\n

Avez-vous déjà écrit du code Go qui devait comparer deux structures, deux slices ou deux maps, et obtenu une erreur de compilation : invalid operation: cannot compare ? Si oui, vous n'êtes pas seul. C'est l'une des questions les plus populaires sur Stack Overflow (des dizaines de milliers de vues !), qui déroute même les développeurs expérimentés passés à Go depuis d'autres langages.

\n\n

Dans cet article, nous allons une fois pour toutes comprendre comment comparer correctement les types de données composites en Go. Vous apprendrez pourquoi == ne fonctionne pas toujours, quand utiliser reflect.DeepEqual, et comment écrire votre propre fonction de comparaison efficace. C'est parti !

\n\n

Pourquoi la comparaison simple avec == ne fonctionne-t-elle pas toujours ?

\n\n

En Go, l'opérateur == ne fonctionne que pour les types comparables (comparable). Ceux-ci incluent :

\n\n
    \n
  • Les types de base : int, string, bool, float, etc.
  • \n
  • Les pointeurs (pointer)
  • \n
  • Les canaux (channel)
  • \n
  • Les interfaces (si les types dynamiques sont comparables)
  • \n
  • Les structures dont tous les champs sont comparables
  • \n
  • Les tableaux (array), si l'élément du tableau est comparable
  • \n
\n\n

En revanche, les slices et les maps ne sont pas comparables directement avec ==. Tenter de le faire entraînera une erreur de compilation. Pourquoi ? Parce qu'un slice est un type de référence qui inclut un pointeur vers les données, la longueur et la capacité. Deux slices peuvent être "égaux" en contenu, mais avoir des structures internes différentes.

\n\n
package main\n\nimport "fmt"\n\nfunc main() {\n    a := []int{1, 2, 3}\n    b := []int{1, 2, 3}\n    \n    // Erreur de compilation !\n    // fmt.Println(a == b) \n    \n    fmt.Println("Fonctionne uniquement avec nil :")\n    fmt.Println(a == nil) // false\n    fmt.Println(b == nil) // false\n}
\n\n

Il en va de même pour les maps. La seule chose que vous pouvez vérifier avec == est l'égalité avec nil.

\n\n

Comparaison des structures (struct) en Go

\n\n

La comparaison des structures est le cas le plus délicat. Si tous les champs de votre structure sont de types comparables, alors == fonctionne !

\n\n
type Person struct {\n    Name string\n    Age  int\n}\n\nfunc main() {\n    p1 := Person{"Alice", 30}\n    p2 := Person{"Alice", 30}\n    \n    fmt.Println(p1 == p2) // true — ça marche !\n}
\n\n

Mais le problème survient lorsque la structure contient un slice ou une map :

\n\n
type PersonWithHobbies struct {\n    Name    string\n    Age     int\n    Hobbies []string  // slice — type non comparable\n}\n\nfunc main() {\n    p1 := PersonWithHobbies{"Bob", 25, []string{"reading", "coding"}}\n    p2 := PersonWithHobbies{"Bob", 25, []string{"reading", "coding"}}\n    \n    // Erreur de compilation !\n    // fmt.Println(p1 == p2)\n}
\n\n

Dans ce cas, le compilateur Go générera une erreur : struct containing []string cannot be compared.

\n\n

Solution n°1 : reflect.DeepEqual — universel mais lent

\n\n

Le moyen le plus simple de comparer des types complexes est d'utiliser la fonction reflect.DeepEqual de la bibliothèque standard de Go. Elle parcourt récursivement les structures, slices et maps et compare leur contenu.

\n\n
import (\n    "fmt"\n    "reflect"\n)\n\nfunc main() {\n    // Comparaison de slices\n    a := []int{1, 2, 3}\n    b := []int{1, 2, 3}\n    fmt.Println(reflect.DeepEqual(a, b)) // true\n    \n    // Comparaison de maps\n    m1 := map[string]int{"a": 1, "b": 2}\n    m2 := map[string]int{"a": 1, "b": 2}\n    fmt.Println(reflect.DeepEqual(m1, m2)) // true\n    \n    // Comparaison de structures avec des champs non comparables\n    p1 := PersonWithHobbies{"Bob", 25, []string{"reading"}}\n    p2 := PersonWithHobbies{"Bob", 25, []string{"reading"}}\n    fmt.Println(reflect.DeepEqual(p1, p2)) // true\n}
\n\n

<

Blogs

Book Recommendations