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


121

Je n'ai pas trouvé de bonne ressource pour utiliser les interface{}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 interface{}?

questions spécifiques:

  • comment obtenir le "vrai" type de w?
  • existe-t-il un moyen d'obtenir la représentation sous forme de chaîne d'un type?
  • existe-t-il un moyen d'utiliser la représentation sous forme de chaîne d'un type pour convertir une valeur?

Réponses:


99

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 des assertions de type .


vous avez absolument raison! Merci! avez-vous un aperçu sur les types représentation chaîne de types?
cc young le

12
Vérifiez reflect.TypeOf.
Dmitri Goldring

@DmitriGoldring Cela répond au moins à la question dans le titre des sujets. Cette réponse non. Merci beaucoup.
C4d

130

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.")
}

Merci pour ça. mais toujours pas tout à fait là. dans l'exemple, comment forcer var w dans un int?
cc young le

3
L'exemple de Mue fait la même chose, mais dans un commutateur de type au lieu d'une instruction if. Dans le cas «int», «v» sera un entier. dans 'case float64', 'v' sera un float64, etc.
jimt

droite. avait oublié la syntaxe var. (type), qui est sournoise et cool
cc young

51

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


10
Et si vous voulez juste obtenir une chaîne ou un type (par exemple pour imprimer dans le bloc par défaut d'un lien de changement de type dans la réponse de Mue, vous pouvez simplement utiliser fmtle format "% T" au lieu d'utiliser directement reflect.
Dave C

16

Voici un exemple de décodage d'une carte générique en utilisant à la fois le commutateur et la réflexion, donc si vous ne correspondez pas au type, utilisez la réflexion pour le comprendre, puis ajoutez le type la prochaine fois.

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)             
    }
}

6

Les commutateurs de type 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")
}

2

Je vais proposer un moyen de renvoyer un booléen basé sur le passage d'un argument d'une réflexion Kinds à un récepteur de type local (car je n'ai rien trouvé de tel).

Tout d'abord, 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 prendre n'importe quel type 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 affirme contre un reflect.Kind:

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

Cela nous permet d'appeler ce qui suit:

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")
}

Vous pouvez voir une version plus longue et fonctionnelle ici: https://play.golang.org/p/EIAp0z62B7


1

Il existe plusieurs façons d'obtenir une représentation sous forme de chaîne d'un type. Les commutateurs peuvent également être utilisés avec les types d'utilisateurs:

var user interface{}
user = User{name: "Eugene"}

// .(type) can only be used inside a switch
switch v := user.(type) {
case int:
    // Built-in types are possible (int, float64, string, etc.)
    fmt.Printf("Integer: %v", v)
case User:
    // User defined types work as well  
    fmt.Printf("It's a user: %s\n", user.(User).name)
}

// You can use reflection to get *reflect.rtype
userType := reflect.TypeOf(user)
fmt.Printf("%+v\n", userType)

// You can also use %T to get a string value
fmt.Printf("%T", user)

// You can even get it into a string
userTypeAsString := fmt.Sprintf("%T", user)

if userTypeAsString == "main.User" {
    fmt.Printf("\nIt's definitely a user")
}

Lien vers une aire de jeux: https://play.golang.org/p/VDeNDUd9uK6

En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.