Menu

Assertion de type en Golang : x.(T), comma-ok et type switch

Une assertion de type récupère la valeur concrète contenue dans une interface. Découvrez x.(T), la forme comma-ok qui ne provoque jamais de panic, l'assertion vers une autre interface, les type switches, et errors.As pour les erreurs enveloppées.

Cette page contient des éditeurs exécutables - modifiez, exécutez et voyez la sortie instantanément.

x.(T) : récupérer la valeur d'une interface

Une valeur interface cache le type concret qu'elle contient. Une assertion de type x.(T) le redemande.

Sortie :

gopher 6
0 false
string of length 6

x doit avoir un type interface. Une assertion sur un type concret ne compile pas : invalid operation: s (variable of type string) is not an interface.

La forme à une valeur provoque un panic

Quand l'assertion est fausse, la forme à une seule valeur provoque un panic avec un message qui nomme les deux types :

Sortie :

recovered: interface conversion: interface {} is int, not string

N'utilisez la forme à une valeur que lorsqu'un type différent serait une erreur de programmation sur laquelle vous voulez planter. Partout ailleurs, utilisez comma-ok. En cas d'échec, comma-ok donne la valeur zéro de T et false.

Une assertion sur une interface nil échoue aussi : var v any; v.(string) provoque le panic interface conversion: interface {} is nil, not string, et la forme comma-ok renvoie "", false.

Assertion vers une autre interface

T peut être un type interface. L'assertion réussit alors si la valeur dynamique implémente T, et le résultat garde la même valeur dynamique. C'est ainsi que la bibliothèque standard teste des capacités facultatives.

io.Copy vérifie si sa source implémente io.WriterTo et l'utilise si c'est le cas. fmt vérifie Stringer et error. Ce motif permet à une petite interface de rester petite tout en laissant les appelants profiter d'implémentations plus riches.

Type switch

Quand une valeur peut être de plusieurs types, un type switch remplace une chaîne d'assertions. x.(type) n'est valide qu'à l'intérieur d'un switch.

Sortie :

hi
integer 7
integer 8
3.14
nil
error: boom
unhandled []int

Règles à connaître :

  • Dans un cas avec un seul type, x a ce type. Dans un cas qui liste plusieurs types, et dans default, x a le type de l'interface d'origine (any ici).
  • Les cas sont testés dans l'ordre. Placez les interfaces plus spécifiques avant les plus larges, puisqu'une valeur peut en satisfaire plusieurs.
  • case nil ne correspond qu'à une interface nil, pas à une interface contenant un pointeur nil.
  • Il n'y a pas de fallthrough dans un type switch.

errors.As : l'assertion pour les erreurs enveloppées

Les erreurs sont souvent enveloppées avec du contexte : fmt.Errorf("load config: %w", err). Une assertion de type directe ne regarde que l'erreur la plus extérieure et rate celle qui est à l'intérieur. errors.As parcourt la chaîne.

Sortie :

type assertion finds it: false
errors.As finds it: open /no/such/file

N'utilisez une assertion de type sur des erreurs que si vous savez que l'erreur n'est pas enveloppée, ce qui en pratique n'arrive presque jamais. La page sur les erreurs personnalisées couvre errors.As, errors.Is et la définition de vos propres types d'erreur.

Assertions, conversions ou génériques

Vous avezVous voulezUtilisez
un intun float64une conversion : float64(n)
un any qui contient un intl'intune assertion : v.(int)
un any de plusieurs types possiblesbrancher selon le typeun type switch
une error peut-être enveloppéeun type d'erreur préciserrors.As
une fonction qui marche pour de nombreux typesla sécurité à la compilationles génériques

Du code rempli de any et de type switches est souvent le signe que les génériques ou une vraie interface exprimeraient mieux l'intention et détecteraient les erreurs à la compilation.

Erreurs courantes

  • Utiliser la forme qui panique sur des données non fiables. JSON décodé, valeurs de map de type any, entrées de plugins : toujours comma-ok.
  • Faire une assertion vers le mauvais type numérique. Les nombres JSON se décodent dans un any en float64, donc v.(int) échoue sur eux.
  • Faire une assertion vers un type valeur quand un pointeur est stocké. Si l'interface contient un *User, v.(User) échoue. Faites l'assertion v.(*User).
  • Des assertions de type sur des erreurs. Utilisez errors.As.

Questions fréquentes

Qu'est-ce qu'une assertion de type en Go ?

Une expression x.(T)x est une valeur interface. Si T est un type concret, elle renvoie la valeur stockée dans x en tant que T. Si T est un type interface, elle vérifie que la valeur stockée implémente aussi T. La forme à une valeur provoque un panic quand la vérification échoue ; la forme à deux valeurs v, ok := x.(T) l'indique dans ok.

Comment vérifier le type d'une valeur interface en Go ?

Utilisez un type switch : switch v := x.(type) { case int: ...; case string: ...; default: ... }. Dans chaque cas, v a le type de ce cas. Pour un seul type, l'assertion comma-ok s, ok := x.(string) est plus courte. fmt.Printf("%T", x) affiche le nom du type pour le débogage.

Quelle est la différence entre une assertion de type et une conversion de type en Go ?

Une conversion T(x) transforme une valeur d'un type en un autre, comme float64(n) ; le compilateur décide si elle est permise, et elle ne peut pas échouer à l'exécution. Une assertion x.(T) ne fonctionne que sur des valeurs interface et vérifie à l'exécution quel type est stocké à l'intérieur. Vous ne pouvez pas écrire int(x) pour un any qui contient un int ; il vous faut x.(int).

Faut-il utiliser une assertion de type pour vérifier le type d'une erreur ?

Non. Utilisez errors.As(err, &target). Une assertion directe err.(*MyError) ne regarde que l'erreur extérieure, donc elle échoue dès que l'erreur est enveloppée avec fmt.Errorf("...: %w", err). errors.As parcourt la chaîne d'enveloppement.

Coddy programming languages illustration

Apprendre à coder avec Coddy

COMMENCER