go - sitename - variable del snippet
Cómo verificar el tipo de variable en tiempo de ejecución en el idioma Go (5)
Tengo pocas funciones C declaradas así
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 esos como una función Go como esta
func (e *Easy)SetOption(option Option, param interface{})
así que necesito poder verificar el tipo de param 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)?
La respuesta de @Darius es el método más idiomático (y probablemente más eficiente). 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 puede obtener un valor reflect.Kind
que es un tipo uint
: http://golang.org/pkg/reflect/#Kind
A continuación, puede hacer comprobaciones de los tipos fuera de un bloque de conmutadores, de esta manera:
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, esta no es probablemente la forma preferida de hacerlo, pero es bueno saber opciones alternativas.
La respuesta de quux00 solo dice acerca de la comparación de tipos básicos.
Si necesita comparar los tipos que definió, no debe usar reflect.TypeOf(xxx)
. En su lugar, use reflect.TypeOf(xxx).Kind()
.
Hay dos categorías de tipos:
- tipos directos (los tipos que definió directamente)
- tipos básicos (int, float64, struct, ...)
Aquí hay 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 puede ver, reflect.TypeOf(xxx)
devuelve los tipos directos que puede desear utilizar, mientras que 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")
}
Parece que Go tiene una forma especial de switch dedicada a esto (se llama type switch ):
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)))
}
}
Qué hay de malo en
func (e *Easy)SetStringOption(option Option, param string)
func (e *Easy)SetLongOption(option Option, param long)
¿y así?
Vea las aserciones de tipo aquí:
http://golang.org/ref/spec#Type_assertions
Solo afirmaría un tipo razonable (cadena, uint64), etc. y lo mantendría lo más suelta posible, realizando una conversión al tipo nativo al final.