Qu'est-ce que la somme de types et comment la réaliser en Go?
sobes.tech IA
Réponse de l'IA
La somme de types (ou union étiquetée, union disjonctive) est un type de données qui peut prendre la valeur d'une de plusieurs options prédéfinies. Contrairement au produit de types (structures), où la valeur contient tous les champs simultanément, la somme de types ne contient qu'une seule des valeurs possibles.
En Go, il n'y a pas de support direct pour les sommes de types comme dans des langages comme Haskell ou Rust (enum). La somme de types peut être émulation de plusieurs manières :
-
Interfaces et assertion de type (Type Assertion) :
Créer une interface que toutes les options possibles implémentent. La valeur de la somme de types sera cette interface, et pour déterminer l'option concrète, on utilise l'assertion de type ou
type switch.package main import "fmt" // Shape - interface représentant la somme de types type Shape interface { Area() float64 } // Circle - une des options type Circle struct { Radius float64 } func (c Circle) Area() float64 { return 3.14 * c.Radius * c.Radius } // Rectangle - une autre option type Rectangle struct { Width, Height float64 } func (r Rectangle) Area() float64 { return r.Width * r.Height } func main() { shapes := []Shape{Circle{Radius: 5}, Rectangle{Width: 3, Height: 4}} for _, s := range shapes { // Utilisation de type switch pour déterminer l'option switch v := s.(type) { case Circle: fmt.Printf("Cercle avec rayon %.2f, aire : %.2f\n", v.Radius, v.Area()) case Rectangle: fmt.Printf("Rectangle avec dimensions %.2f x %.2f, aire : %.2f\n", v.Width, v.Height, v.Area()) default: fmt.Println("Forme inconnue") } } } -
Structures avec drapeaux booléens (rarement utilisées) :
La structure contient des champs pour toutes les options possibles et des drapeaux booléens pour indiquer quelle option est active. C'est dangereux et difficile à maintenir.
package main import "fmt" type Result struct { Value int // Champ pour résultat réussi Err error // Champ pour erreur IsValue bool // Drapeau indiquant si Value est actif IsErr bool // Drapeau indiquant si Err est actif } func Process(input int) Result { if input > 0 { return Result{Value: input * 2, IsValue: true} } return Result{Err: fmt.Errorf("nombre négatif : %d", input), IsErr: true} } func main() { res1 := Process(10) if res1.IsValue { fmt.Printf("Résultat : %d\n", res1.Value) } else if res1.IsErr { fmt.Printf("Erreur : %v\n", res1.Err) } res2 := Process(-5) if res2.IsValue { fmt.Printf("Résultat : %d\n", res2.Value) } else if res2.IsErr { fmt.Printf("Erreur : %v\n", res2.Err) } } -
Structures avec valeur nulle pour les champs non actifs (souvent utilisé pour Optional/Result) :
La structure contient des champs pour toutes les options possibles, mais un seul d'entre eux sera non nul. Fonctionne bien avec des pointeurs ou des types ayant une valeur "nulle" claire.
package main import "fmt" // Option - émulation de Some/None du type optionnel type Option struct { Value *int // Non nul s'il y a une valeur } // None crée une valeur Option nulle func None() Option { return Option{} } // Some crée une Option avec une valeur func Some(val int) Option { return Option{Value: &val} } func main() { opt1 := Some(10) if opt1.Value != nil { fmt.Printf("Valeur : %d\n", *opt1.Value) } else { fmt.Println("Pas de valeur") } opt2 := None() if opt2.Value != nil { fmt.Printf("Valeur : %d\n", *opt2.Value) } else { fmt.Println("Pas de valeur") } }
La méthode la plus idiomatique et sûre pour émuler des sommes de types en Go est d'utiliser interfaces et type switch. Cela garantit qu'une seule option est présente et assure la sécurité de type lors de son utilisation.