检查reflect.Kind on interface {}返回无效结果

时间:2018-03-05 12:12:38

标签: go reflection types slice

我对golang反映行为感到困惑。

所以基本上我有一个名为src的切片,其类型为[]interface{}。我想得到每个元素的实际类型。这就是我所做的:

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

我不明白为什么{@ 1}}未检测到元素"noval"的类型,而是从string调用default

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

请有人赐教,请提前谢谢。

1 个答案:

答案 0 :(得分:4)

src是一个元素类型为interface{}的切片。因此,您获得的每个元素都是静态类型interface{},因此他们的#34;类型&#34;将是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

如果你想要&#34;包裹&#34;界面中的元素,使用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

另请注意,您已经&#34;切换&#34;超过种类的值,而不是实际的类型。这意味着多种类型的值可能会在特定情况下结束,如下所示:

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 &#34; kind&#34; ,但其类型不是{ {1}}但是string。这可能是也可能不是你想要的。如果您想区分mystrstring类型的值,那么您应该&#34;切换&#34;在这个例子的实际类型中:

mystr

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

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

如您所见,value noval is string value 0 is int value <nil> is nil value my is mystr 被检测为"nova"类型的值,而string被正确检测为mystr("my")类型的值。

另请注意,对于您尝试做的事情,您不需要反思,只需使用type switch

mystr

输出(在Go Playground上尝试):

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