2011-06-16 31 views
77

No he encontrado un buen recurso para usar los tipos interface{}. Por ejemplo¿Cómo determinar el tipo "real" de un valor de interfaz {}?

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

¿Conoce una buena introducción al uso de Go interface{}?

preguntas específicas:

  • ¿cómo puedo obtener el "verdadero" Tipo de w?
  • ¿hay alguna forma de obtener la representación de cadena de un tipo?
  • ¿hay alguna forma de utilizar la representación de cadena de un tipo para convertir un valor?

Respuesta

62

Su ejemplo no funciona. Aquí hay una versión simplificada.

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 

Utiliza Type assertions.

+0

tienes toda la razón! ¡Gracias! ¿tiene alguna idea sobre las representaciones de tipos de cadenas de tipos? –

+4

Echa un vistazo a 'reflect.TypeOf'. –

83

También se puede hacer interruptores de tipo:

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

gracias por eso. pero todavía no del todo allí. en el ejemplo, ¿cómo forzar var w en un int? –

+0

no importa. @peterSO lo consiguió. –

+3

El ejemplo de Mue hace lo mismo, pero en un modificador de tipo en lugar de una instrucción if. En el 'caso int', 'v' será un número entero. en 'caso float64', 'v' será un float64, etc. – jimt

35

Puede utilizar la reflexión (reflect.TypeOf()) para obtener el tipo de algo, y el valor que da (Type) tiene una representación de cadena (String método) que se puede imprimir

+5

Y si solo desea obtener una cadena o un tipo (por ejemplo, para imprimir en el bloque predeterminado de un enlace de cambio de tipo en [respuesta de Mue]) (http: // stackoverflow.com/a/6373523/55504) puede usar el formato "% T" de 'fmt' en lugar de usar directamente' reflect'. –

5

interruptores de tipo también se pueden utilizar con la materia de reflexión:

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

Aquí es un ejemplo de decodificación de un mapa genérico utilizando tanto el switch y la reflexión, por lo que si no hace coincidir el tipo, uso reflexión a la figura salir y luego agregar el tipo la próxima vez.

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

Voy a ofrecer una manera de devolver un valor lógico basado en un argumento que pasa de una clase de reflexión a un receptor de tipo local (porque no podía encontrar nada como esto).

En primer lugar, declaramos nuestro tipo anónimo de tipo reflect.Value:

type AnonymousType reflect.Value 

A continuación, añadir un constructor para nuestro tipo local de AnonymousType que puede tomar en cualquier tipo de potencial (como una interfaz):

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

a continuación añadimos una función de nuestra estructura AnonymousType que se afirma contra un reflect.Kind:

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

Esto nos permite llamar a los siguientes:

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

puede ver una versión más larga de trabajo aquí: https://play.golang.org/p/EIAp0z62B7

Cuestiones relacionadas