【问题标题】:Checking reflect.Kind on interface{} return invalid result检查 interface{} 上的 reflect.Kind 返回无效结果
【发布时间】:2018-08-13 02:18:33
【问题描述】:

我对 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

我不明白为什么 "noval" 的元素类型未被检测为 string,而是从 switch 调用 default

同样0 值应该被标识为reflect.Int,但default 被再次调用。

谁能给我指点一下,先谢谢了。

【问题讨论】:

    标签: go reflection types slice


    【解决方案1】:

    src 是一个元素类型为interface{} 的切片。所以你获得的每个元素都是静态类型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
    

    如果你想要界面中的“包裹”元素,请使用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 类型的值,那么您应该“切换”实际的 type 值,如下例所示:

    } 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
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2014-03-01
      • 2011-12-30
      • 2012-01-08
      • 1970-01-01
      • 2020-08-21
      • 1970-01-01
      • 1970-01-01
      • 2023-04-10
      相关资源
      最近更新 更多