J'utilise le package Reflect pour déterminer le type d'un champ struct est interface{}

Je veux faire la comparaison comme ceci (où t est un reflect.Type):

if  t == reflect.TypeOf(interface{}) {

}

Le problème est que le compilateur se plaint: type interface {} is not an expression.

Est-il possible de vérifier si le type d'un champ struct est un interface{}?

3
F21 17 janv. 2017 à 13:27

2 réponses

Meilleure réponse

interface{} est un type et reflect.TypeOf() attend une valeur. Vous ne pouvez donc pas lui passer le littéral interface{}. Vous ne pouvez transmettre qu'une valeur.

Revenons à la question initiale. Voyons un exemple struct:

type My struct {
    A int
    B interface{}
    C io.Reader
}

Vous voulez savoir si le type d'un champ est interface{}. Acquérir le reflect.Type du type struct, puis vous pouvez accéder aux champs en utilisant Type.Field() ou Type.FieldByName().

Cela vous donne une valeur de type reflect.StructField qui stocke le type du champ .

Jusqu'ici tout va bien. Mais à quoi devrions-nous le comparer? interface{} est un type d'interface avec 0 méthode. Vous ne pouvez pas avoir (instancier) une valeur de ce type. Vous ne pouvez avoir que des valeurs de types concrets, mais oui, elles peuvent être enveloppées dans un type d'interface.

Vous pouvez utiliser Type.Kind et le comparer à reflect.Interface, qui vous indique s'il s'agit d'une interface, mais c'est true pour tous les types d'interface. Vous pouvez également vérifier s'il a 0 méthode avec Type.NumMethod(), qui doit être 0 pour interface{}, mais d'autres interfaces peuvent également avoir 0 méthode ...

Vous pouvez utiliser Type.Name, mais comme interface{} est un type sans nom , son nom est la chaîne vide "" (et il existe d'autres types sans nom). Vous pouvez utiliser Type.String() qui renvoie "interface {}" pour l'interface vide:

t := reflect.TypeOf(My{})

for i := 0; i < t.NumField(); i++ {
    f := t.Field(i)
    fmt.Printf("Field %q, type: %-12v, type name: %-8q, is interface{}: %v\n",
        f.Name, f.Type,
        f.Type.Name(),
        f.Type.String() == "interface {}",
    )
}

Sortie (essayez-le sur Go Playground):

Field "A", type: int         , type name: "int"   , is interface{}: false
Field "B", type: interface {}, type name: ""      , is interface{}: true
Field "C", type: io.Reader   , type name: "Reader", is interface{}: false

Vous trouverez peut-être cette question connexe intéressante / utile: Identifiez les types non intégrés à l'aide de refléter

5
Community 23 mai 2017 à 11:55

Vous pouvez obtenir le type de l'interface Y en créant une instance nil et en utilisant la réflexion:

yType := reflect.TypeOf((*Y)(nil)).Elem()

Puis utilisez l'expression

reflect.TypeOf(x).Implements(yType)

Pour vérifier si le type implémente l'interface.

Les interfaces elles-mêmes ne peuvent pas être instanciées. L'interface {} interface qui est l'interface vide est implémentée par tous les types donc tous les champs l'implémentent.

https://play.golang.org/p/gRfheIW_9Y

En fait, cela fonctionne également avec l'interface vide {} elle-même mais cela retournera toujours vrai (si je ne manque pas quelque chose):

https://play.golang.org/p/29rWP4LtIo

6
Christian 29 janv. 2018 à 13:53