我对 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
。这可能是也可能不是您想要的。如果你想区分 string
和 mystr
类型的值,那么你应该像这样“切换”值的实际类型示例:
} 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/