如何在Go语言中检查运行时的变量类型

Dar*_*kas 56 go

我有很少的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);
Run Code Online (Sandbox Code Playgroud)

我想将这些作为一个Go函数公开

func (e *Easy)SetOption(option Option, param interface{})
Run Code Online (Sandbox Code Playgroud)

所以我需要能够在运行时检查param类型.我该怎么做,这是个好主意(如果不是这种情况下的好习惯)?

Dar*_*kas 84

似乎Go有专门用于此的特殊形式的开关(称为类型开关):

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)))
    } 
}
Run Code Online (Sandbox Code Playgroud)

  • 这个语法只能用在`switch`中吗?例如,如果我只关心 1 个案例,那么切换可能就太过分了? (3认同)
  • @bmdelacruz someVariable 必须是一个接口才能对其进行类型断言 (3认同)
  • @NathanH 是的,这种方式仅适用于 switch(用 Go 1.10 测试) (2认同)
  • 其实没有 语句“ someVariable。(SomeType)”实际上可能会产生另一个布尔变量,可用于检查类型声明是否成功,即“ someTypeVariable,isTypeSomeType:= someVariable。(SomeType)”。有关类型断言的信息位于[documentation](https://golang.org/ref/spec#Type_assertions)上。 (2认同)

quu*_*x00 51

@Darius的答案是最惯用的(可能更高性能)方法.一个限制是您要检查的类型必须是类型interface{}.如果使用具体类型,它将失败.

在运行时确定某些类型的另一种方法,包括具体类型,是使用Go reflect包.链接TypeOf(x).Kind()在一起你可以获得reflect.Kind一个uint类型的值:http://golang.org/pkg/reflect/#Kind

然后,您可以检查交换机块之外的类型,如下所示:

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")
}
Run Code Online (Sandbox Code Playgroud)

打印出来的:

reflect.Kind: int
reflect.Kind: float32
reflect.Kind: string
>> x is int
>> y is float32
>> z is string
Run Code Online (Sandbox Code Playgroud)

同样,这可能不是首选方法,但了解替代选项会很好.

  • @karantan根据quux00的代码需要.Kind()。否则你会得到编译时错误。https://golang.org/pkg/reflect/#Kind Kind 表示 Type 表示的特定类型 https://golang.org/pkg/reflect/#TypeOf 返回类型接口{} (2认同)

Del*_*ted 11

请参阅此处的类型断言:

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

我只断言一个合理的类型(字符串,uint64)等,并保持尽可能宽松,最后执行转换为本机类型.

  • 答案应该是完整的,而不仅仅是链接.请充实这个答案. (39认同)
  • 注意:这不适用于具体类型,仅适用于接口类型. (4认同)
  • 这是对“如何在运行时确定变量类型”而不是“如何在运行时检查变量类型”问题的答案。 (4认同)

Mew*_*ewX 5

quux00的答案仅说明有关比较基本类型的信息。

如果您需要比较定义的类型,则不应使用reflect.TypeOf(xxx)。而是使用reflect.TypeOf(xxx).Kind()

有两类类型:

  • 直接类型(您直接定义的类型)
  • 基本类型(int,float64,struct等)

这是一个完整的示例:

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")
}
Run Code Online (Sandbox Code Playgroud)

输出为:

main.Vertex
struct
main.MyFloat
float64
Not equal typeOf
Not equal kind
Equal typeOf
Equal kind
Run Code Online (Sandbox Code Playgroud)

如您所见,reflect.TypeOf(xxx)返回您可能要使用的直接类型,而reflect.TypeOf(xxx).Kind()返回基本类型。


这是结论。如果需要与基本类型进行比较,请使用reflect.TypeOf(xxx).Kind(); 如果需要与自定义类型进行比较,请使用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")
}
Run Code Online (Sandbox Code Playgroud)