如何在围棋语言运行时检查变量类型

像这样声明的 C 函数很少

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

我想揭露这些作为一个去功能这样

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

所以我需要能够在运行时检查 Param类型。我如何做到这一点,这是一个好主意(如果不是什么是良好的做法在这种情况下) ?

185872 次浏览

See type assertions here:

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

I'd assert a sensible type (string, uint64) etc only and keep it as loose as possible, performing a conversion to the native type last.

func (e *Easy)SetOption(option Option, param interface{}) {
if s, ok := param.(string); ok {
// s is string here
}
// else...
}

What's wrong with

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

and so on?

It seems that Go have special form of switch dedicate to this (it is called 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)))
}
}

The answer by @Darius is the most idiomatic (and probably more performant) method. One limitation is that the type you are checking has to be of type interface{}. If you use a concrete type it will fail.

An alternative way to determine the type of something at run-time, including concrete types, is to use the Go reflect package. Chaining TypeOf(x).Kind() together you can get a reflect.Kind value which is a uint type: http://golang.org/pkg/reflect/#Kind

You can then do checks for types outside of a switch block, like so:

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

Which prints outs:

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

Again, this is probably not the preferred way to do it, but it's good to know alternative options.

quux00's answer only tells about comparing basic types.

If you need to compare types you defined, you shouldn't use reflect.TypeOf(xxx). Instead, use reflect.TypeOf(xxx).Kind().

There are two categories of types:

  • direct types (the types you defined directly)
  • basic types (int, float64, struct, ...)

Here is a full example:

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

The output would be:

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

As you can see, reflect.TypeOf(xxx) returns the direct types which you might want to use, while reflect.TypeOf(xxx).Kind() returns the basic types.


Here's the conclusion. If you need to compare with basic types, use reflect.TypeOf(xxx).Kind(); and if you need to compare with self-defined types, 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")
}