go - 检查 interface{} 上的 reflect.Kind 返回无效结果

标签 go reflection types slice

我对 Go 反射(reflect)行为有一些疑问。

我在 []interface{} 类型中定义了一个名为 src 的 slice 。我想获取 slice 中每个元素的实际类型。这就是我所做的:

src := []interface{}{"noval", 0, nil}
srcType := reflect.ValueOf(src)

for i := 0; i < srcType.Len(); i++ {
    each := srcType.Index(i)

    if each.Interface() == nil {
        fmt.Println("value", each.Interface(), "is nil")
    } else {
        switch each.Kind() {
        case reflect.String:
            fmt.Println("value", each.Interface(), "is string")
        case reflect.Int, reflect.Int16:
            fmt.Println("value", each.Interface(), "is int")
        default:
            fmt.Println("value", each.Interface(), "is ?")
        }
    }
}

输出:

value noval is ?
value 0 is ?
value <nil> is nil

由于某些原因,元素 "noval" 的数据类型未被检测为 string,因此 default block 在切换

此外,0 值应标识为 reflect.Int,但会再次调用 default block 。

谁能赐教,先谢谢了。

最佳答案

src 是一个元素类型为 interface{} 的 slice 。因此,您获得的每个元素都是静态类型 interface{},因此它们的“种类”将是 reflect.Interface。添加一个新的 reflect.Interface 案例将显示:

case reflect.Interface:
    fmt.Println("value", each.Interface(), "is interface")

输出将是(在 Go Playground 上尝试):

value noval is interface
value 0 is interface
value <nil> is nil

如果你想在界面中使用“wrapped”元素,使用Value.Elem() :

} else if each.Kind() == reflect.Interface {
    switch each.Elem().Kind() {
    case reflect.String:
        fmt.Println("value", each.Interface(), "is string")
    case reflect.Int, reflect.Int16:
        fmt.Println("value", each.Interface(), "is int")
    default:
        fmt.Println("value", each.Interface(), "is ?")
    }
}

然后输出将是(在 Go Playground 上尝试):

value noval is string
value 0 is int
value <nil> is nil

另请注意,您正在“切换”值的种类,而不是它们的实际类型。这意味着多种类型的值可能会在特定情况下结束,例如在这种情况下:

type mystr string
src := []interface{}{"noval", 0, nil, mystr("my")}
srcType := reflect.ValueOf(src)

// ...

此输出将是(在 Go Playground 上尝试):

value noval is string
value 0 is int
value <nil> is nil
value my is string

mystr("my") 被检测为 string,因为它是 string "kind",但它的类型不是string,而是mystr。这可能是也可能不是您想要的。如果你想区分 stringmystr 类型的值,那么你应该像这样“切换”值的实际类型示例:

} else if each.Kind() == reflect.Interface {
    switch each.Elem().Type() {
    case reflect.TypeOf(""):
        fmt.Println("value", each.Interface(), "is string")
    case reflect.TypeOf(0):
        fmt.Println("value", each.Interface(), "is int")
    case reflect.TypeOf(mystr("")):
        fmt.Println("value", each.Interface(), "is mystr")
    default:
        fmt.Println("value", each.Interface(), "is ?")
    }
}

然后输出将是(在 Go Playground 上尝试):

value noval is string
value 0 is int
value <nil> is nil
value my is mystr

如您所见,"nova" 被检测为 string 类型的值,并且 mystr("my") 被正确检测到作为 mystr 类型的值。

另请注意,对于您要尝试执行的操作,您不需要反射,只需使用 type switch :

src := []interface{}{"noval", 0, nil}
for _, v := range src {
    switch v.(type) {
    case string:
        fmt.Println("value", v, "is string")
    case int:
        fmt.Println("value", v, "is int")
    case nil:
        fmt.Println("value", v, "is nil")
    default:
        fmt.Println("value", v, "is ?")
    }
}

输出(在 Go Playground 上尝试):

value noval is string
value 0 is int
value <nil> is nil

关于go - 检查 interface{} 上的 reflect.Kind 返回无效结果,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49110256/

相关文章:

bash - Debian:如何将错误消息写入文件?

postgresql - postgres 枚举与 golang pgx

go - 惯用缓冲区 os.Stdout

使用反射时的 Java NoSuchFieldError

java - 为什么反射返回两种方法,而只有一种实现?

Java:设置未知数量条目的数组长度

types - golang 类型转换不按预期工作

go - 使用带有标量或 slice 的函数

java - 使用一个类中的方法到一个集合中

arrays - Julia 类型内的数组