web-dev-qa-db-fra.com

Comment déterminer le type "réel" d'une valeur d'interface {}?

Je n'ai pas trouvé de bonne ressource pour utiliser interface{} les types. Par exemple

package main

import "fmt"

func weirdFunc(i int) interface{} {
    if i == 0 {
        return "zero"
    }
    return i
}
func main() {
    var i = 5
    var w = weirdFunc(5)

    // this example works!
    if tmp, ok := w.(int); ok {
        i += tmp
    }

    fmt.Println("i =", i)
}

Connaissez-vous une bonne introduction à l’utilisation de Go's interface{}?

questions spécifiques:

  • comment puis-je obtenir le "vrai" type de w?
  • est-il possible d'obtenir la représentation sous forme de chaîne d'un type?
  • est-il possible d'utiliser la représentation sous forme de chaîne d'un type pour convertir une valeur?
102
cc young

Votre exemple fonctionne. Voici une version simplifiée.

package main

import "fmt"

func weird(i int) interface{} {
    if i < 0 {
        return "negative"
    }
    return i
}

func main() {
    var i = 42
    if w, ok := weird(7).(int); ok {
        i += w
    }
    if w, ok := weird(-100).(int); ok {
        i += w
    }
    fmt.Println("i =", i)
}

Output:
i = 49

Il utilise Assertions de type .

82
peterSO

Vous pouvez également faire des commutateurs de type:

switch v := myInterface.(type) {
case int:
    // v is an int here, so e.g. v + 1 is possible.
    fmt.Printf("Integer: %v", v)
case float64:
    // v is a float64 here, so e.g. v + 1.0 is possible.
    fmt.Printf("Float64: %v", v)
case string:
    // v is a string here, so e.g. v + " Yeah!" is possible.
    fmt.Printf("String: %v", v)
default:
    // And here I'm feeling dumb. ;)
    fmt.Printf("I don't know, ask stackoverflow.")
}
107
themue

Vous pouvez utiliser la réflexion (reflect.TypeOf()) pour obtenir le type de quelque chose. La valeur qu'il donne (Type) a une représentation sous forme de chaîne (méthode String) que vous pouvez imprimer. .

46
newacct

Voici un exemple de décodage d'une carte générique à la fois avec switch et réflexion. Si vous ne correspondez pas au type, utilisez la réflexion pour la comprendre, puis ajoutez le type lors de la prochaine utilisation.

var data map[string]interface {}

...

for k, v := range data {
    fmt.Printf("pair:%s\t%s\n", k, v)   

    switch t := v.(type) {
    case int:
        fmt.Printf("Integer: %v\n", t)
    case float64:
        fmt.Printf("Float64: %v\n", t)
    case string:
        fmt.Printf("String: %v\n", t)
    case bool:
        fmt.Printf("Bool: %v\n", t)
    case []interface {}:
        for i,n := range t {
            fmt.Printf("Item: %v= %v\n", i, n)
        }
    default:
        var r = reflect.TypeOf(t)
        fmt.Printf("Other:%v\n", r)             
    }
}
13
h4ck3rm1k3

Les commutateurs de types peuvent également être utilisés avec des éléments de réflexion:

var str = "hello!"
var obj = reflect.ValueOf(&str)

switch obj.Elem().Interface().(type) {
case string:
    log.Println("obj contains a pointer to a string")
default:
    log.Println("obj contains something else")
}
6
Nikolai Koudelia

Je vais offrir un moyen de renvoyer un booléen basé sur le fait de passer un argument de type de réflexion à un récepteur de type local (car je ne pouvais rien trouver de la sorte).

Premièrement, nous déclarons notre type anonyme de type reflect.Value:

type AnonymousType reflect.Value

Ensuite, nous ajoutons un générateur pour notre type local AnonymousType qui peut accepter n'importe quel type de potentiel (en tant qu'interface):

func ToAnonymousType(obj interface{}) AnonymousType {
    return AnonymousType(reflect.ValueOf(obj))
}

Ensuite, nous ajoutons une fonction pour notre structure AnonymousType qui s’affirme contre un reflect.Kind:

func (a AnonymousType) IsA(typeToAssert reflect.Kind) bool {
    return typeToAssert == reflect.Value(a).Kind()
}

Cela nous permet d’appeler les personnes suivantes:

var f float64 = 3.4

anon := ToAnonymousType(f)

if anon.IsA(reflect.String) {
    fmt.Println("Its A String!")
} else if anon.IsA(reflect.Float32) {
    fmt.Println("Its A Float32!")
} else if anon.IsA(reflect.Float64) {
    fmt.Println("Its A Float64!")
} else {
    fmt.Println("Failed")
}

Peut voir une version plus longue, de travail ici: https://play.golang.org/p/EIAp0z62B7

1
daino3