Leçons du module (4/5)
L'interface Stringer
fmt.Stringer est probablement l'interface standard la plus utilisée dans tous les pays.
La bibliothèque standard de Go. C'est la démonstration parfaite de la puissance
de petites interfaces.
Définition
type Stringer interface {
String() string
}Une seule signature. Tout type qui définit String() string satisfait
ça. Et fmt reconnaît cette interface : lorsque vous passez une valeur à
fmt.Print*, s'il implémente Stringer, le résultat de String()
est utilisé à la place de la représentation par défaut.
Exemple
type Point struct{ X, Y int }
func (p Point) String() string {
return fmt.Sprintf("(%d,%d)", p.X, p.Y)
}
fmt.Println(Point{1, 2}) // (1,2)
fmt.Printf("%v %s\n", Point{3, 4}, Point{5, 6})
// (3,4) (5,6)La même valeur s'imprime avec un formatage personnalisé dans %v, %s, Println,
Sprint, log, etc. Tout cela en définissant simplement une méthode.
Quand cela a du sens
- Types qui modélisent un domaine (identifiants, codes, coordonnées, énumérations).
- Erreurs avec une représentation lisible par l'homme (voir prochaine leçon sur
error). - Les types que vous enregistrez souvent et pour lesquels vous souhaitez un format fixe.
Pas pour tout : si le type est simple et la représentation par défaut c'est bien, n'ajoute pas de bruit.
Types d'énumération : modèle commun avec iota
type Status int
const (
OK Status = iota
WARN
ERR
)
func (s Status) String() string {
switch s {
case OK: return "OK"
case WARN: return "WARN"
case ERR: return "ERR"
default: return "UNKNOWN"
}
}
fmt.Println(OK, WARN, ERR) // OK WARN ERRSans String(), fmt.Println(OK) imprimerait 0. Avec String(),
il imprime le nom symbolique. Le stringer
L'outil génère automatiquement ce modèle.
Attention à la récursion infinie
type T int
func (t T) String() string {
return fmt.Sprintf("%d", int(t)) // OK: cast to int breaks the recursion
}Stringer sur un récepteur pointeur
Si String() possède un récepteur pointeur, seul *T satisfait Stringer.
Avec fmt.Println(t) (une valeur), Go regarde l'ensemble de méthodes de T,
ne le trouve pas et utilise le format par défaut. Pour éviter cela, valeur
Le récepteur est généralement utilisé pour String() (c'est une "vue" ; ce n'est pas le cas).
modifier quoi que ce soit).
Essayez-le
Implémentez String() sur Point pour qu'il renvoie (X,Y).
Afficher l'indice
Utilisez `fmt.Sprintf` pour formater les champs.
Solution disponible après 3 tentatives
Implémentez String() sur un type Status (int) : 0 → 'OK', 1 → 'WARN', sinon → 'ERR'.
Afficher l'indice
Allumez la valeur du récepteur ; n'oubliez pas de fournir une valeur par défaut.
Solution disponible après 3 tentatives
Quelle signature la méthode doit-elle avoir pour satisfaire fmt.Stringer ?
func (x T) ??? {}Récapitulatif
fmt.Stringer = interface { String() string }.- Son implémentation change la façon dont
fmt.Print*représente le type. - Idiomatique pour les énumérations (
iota), les types de domaines, les codes/identifiants. - N'appelez jamais
fmt.Sprintf("%s", t)surtà l'intérieur deString()(récursion). - Convention : récepteur de valeur pour
String()(pas de mutation, évite les "surprises méthode-set").