2011-08-09 19 views
32

tengo pocas funciones C declarados como estoCómo comprobar el tipo de variable en tiempo de ejecución en el lenguaje Ir

CURLcode curl_wrapper_easy_setopt_long(CURL* curl, CURLoption option, long param); 
CURLcode curl_wrapper_easy_setopt_str(CURL* curl, CURLoption option, char* param); 

me gustaría exponer a aquellos como una función de ir así

func (e *Easy)SetOption(option Option, param interface{}) 

por eso es necesario para poder verificar param tipo en tiempo de ejecución. ¿Cómo hago eso y esta es una buena idea (si no es lo que es una buena práctica en este caso)?

Respuesta

11

consulte Tipo afirmaciones aquí:

http://golang.org/ref/spec#Type_assertions

me gustaría valer un tipo sensible (cuerda, uint64), etc solamente y mantenerlo lo más suave posible, llevar a cabo una conversión al tipo nativo pasado.

+9

Las respuestas deben estar completas, no solo en los enlaces. Por favor desarrolla esta respuesta. – Flimzy

+2

nota: Esto no funciona para tipos concretos, solo tipos de interfaz. – darethas

-1

¿Qué hay de malo en

func (e *Easy)SetStringOption(option Option, param string) 
func (e *Easy)SetLongOption(option Option, param long) 

y así sucesivamente?

+0

porque en C biblioteca libCURL tiene una sola función para la configuración de opciones curl_easy_setopt (CURL * curl, opción CURLoption, ...). Pero cgo no es compatible con varargs, así que hice que la función de envoltura en C para cada tipo de parámetro. Creo que la interfaz de Go debería estar lo más cerca de C posible. Si el usuario conoce libCURL (de C u otro idioma), quiero que se sienta como en casa;) –

+0

Tarde en el juego, ¡pero yo discutiría contra ese enfoque! Desea que la biblioteca se sienta como en casa con un usuario * Go *. (El mejor ejemplo de que los puertos directos de bibliotecas de nivel inferior como cURL confunden a las personas es ... PHP) – Nevir

47

Parece que ir a tomar forma especial de interruptor se dedican a esto (que se llama interruptor de tipo):

func (e *Easy)SetOption(option Option, param interface{}) { 

    switch v := param.(type) { 
    default: 
     fmt.Printf("unexpected type %T", v) 
    case uint64: 
     e.code = Code(C.curl_wrapper_easy_setopt_long(e.curl, C.CURLoption(option), C.long(v))) 
    case string: 
     e.code = Code(C.curl_wrapper_easy_setopt_str(e.curl, C.CURLoption(option), C.CString(v))) 
    } 
} 
+0

¿Se puede usar esta sintaxis solo en 'switch'? Por ejemplo, si solo me importa 1 caso, ¿quizás un cambio es excesivo? –

+0

@NathanH Sí, de esta manera funciona solo para el interruptor (probado con Go 1.10) – MewX

36

La respuesta por @Darius es el método más idiomática (y probablemente con más prestaciones). Una limitación es que el tipo que está comprobando debe ser del tipo interface{}. Si usa un tipo concreto, fallará.

Una forma alternativa de determinar el tipo de algo en tiempo de ejecución, incluidos los tipos concretos, es utilizar el paquete Go reflect. Encadenando TypeOf(x).Kind() juntos se puede obtener un valor reflect.Kind que es un tipo uint: http://golang.org/pkg/reflect/#Kind

A continuación, puede hacer controles para los tipos exterior de un bloque de interruptores, así:

import (
    "fmt" 
    "reflect" 
) 

// .... 

x := 42 
y := float32(43.3) 
z := "hello" 

xt := reflect.TypeOf(x).Kind() 
yt := reflect.TypeOf(y).Kind() 
zt := reflect.TypeOf(z).Kind() 

fmt.Printf("%T: %s\n", xt, xt) 
fmt.Printf("%T: %s\n", yt, yt) 
fmt.Printf("%T: %s\n", zt, zt) 

if xt == reflect.Int { 
    println(">> x is int") 
} 
if yt == reflect.Float32 { 
    println(">> y is float32") 
} 
if zt == reflect.String { 
    println(">> z is string") 
} 

que imprime outs:

reflect.Kind: int 
reflect.Kind: float32 
reflect.Kind: string 
>> x is int 
>> y is float32 
>> z is string 

De nuevo, probablemente esta no sea la forma preferida de hacerlo, pero es bueno saber opciones alternativas.

+0

¿Por qué necesita '.Kind()'? Funciona sin eso. – karantan

+0

@karantan Según el código de quux00 .Kind() es necesario. De lo contrario, obtendrá un error de tiempo de compilación. https://golang.org/pkg/reflect/#Kind Un tipo representa el tipo específico de tipo que un tipo representa https://golang.org/pkg/reflect/#TypeOf return type interface {} – Mujibur

0

La respuesta del quux00 solo dice acerca de la comparación de tipos básicos.

Si necesita comparar los tipos que ha definido, no debe usar reflect.TypeOf(xxx). En su lugar, use reflect.TypeOf(xxx).Kind().

Hay dos categorías de tipos:

  • tipos directos (los tipos definidos directamente)
  • tipos básicos (int, float64, estructura, ...)

Aquí es un ejemplo completo:

type MyFloat float64 
type Vertex struct { 
    X, Y float64 
} 

type EmptyInterface interface {} 

type Abser interface { 
    Abs() float64 
} 

func (v Vertex) Abs() float64 { 
    return math.Sqrt(v.X*v.X + v.Y*v.Y) 
} 

func (f MyFloat) Abs() float64 { 
    return math.Abs(float64(f)) 
} 

var ia, ib Abser 
ia = Vertex{1, 2} 
ib = MyFloat(1) 
fmt.Println(reflect.TypeOf(ia)) 
fmt.Println(reflect.TypeOf(ia).Kind()) 
fmt.Println(reflect.TypeOf(ib)) 
fmt.Println(reflect.TypeOf(ib).Kind()) 

if reflect.TypeOf(ia) != reflect.TypeOf(ib) { 
    fmt.Println("Not equal typeOf") 
} 
if reflect.TypeOf(ia).Kind() != reflect.TypeOf(ib).Kind() { 
    fmt.Println("Not equal kind") 
} 

ib = Vertex{3, 4} 
if reflect.TypeOf(ia) == reflect.TypeOf(ib) { 
    fmt.Println("Equal typeOf") 
} 
if reflect.TypeOf(ia).Kind() == reflect.TypeOf(ib).Kind() { 
    fmt.Println("Equal kind") 
} 

la salida sería:

main.Vertex 
struct 
main.MyFloat 
float64 
Not equal typeOf 
Not equal kind 
Equal typeOf 
Equal kind 

Como se puede ver, reflect.TypeOf(xxx) devuelve los tipos directos, que es posible que desee utilizar, mientras reflect.TypeOf(xxx).Kind() devuelve los tipos básicos.


Aquí está la conclusión. Si necesita comparar con tipos básicos, use reflect.TypeOf(xxx).Kind(); y si necesita comparar con tipos autodefinidos, use reflect.TypeOf(xxx).

if reflect.TypeOf(ia) == reflect.TypeOf(Vertex{}) { 
    fmt.Println("self-defined") 
} else if reflect.TypeOf(ia).Kind() == reflect.Float64 { 
    fmt.Println("basic types") 
} 
Cuestiones relacionadas