【问题标题】:How to cast reflect.Value to its type?如何将 reflect.Value 转换为它的类型?
【发布时间】:2013-06-20 04:17:02
【问题描述】:

如何将 reflect.Value 转换为它的类型?

type Cat struct { 
    Age int
}

cat := reflect.ValueOf(obj)
fmt.Println(cat.Type()) // Cat

fmt.Println(Cat(cat).Age) // doesn't compile
fmt.Println((cat.(Cat)).Age) // same

谢谢!

【问题讨论】:

  • Go 没有类型转换。你不能施放任何东西。

标签: reflection go


【解决方案1】:
concreteCat,_ := reflect.ValueOf(cat).Interface().(Cat)

http://golang.org/doc/articles/laws_of_reflection.html 狐狸的例子

type MyInt int
var x MyInt = 7
v := reflect.ValueOf(x)
y := v.Interface().(float64) // y will have type float64.
fmt.Println(y)

【讨论】:

  • 如果你真的了解类型的话。如果您想应用某种盲类型断言,我实际上不确定是否可行。
  • 一种解决方案似乎是保留reflect.Value 原样,只需将所有计算转移到使用反射包,而不希望转换回常规结构。您可以在gongular 中看到这一点。相关:play.golang.org/p/Ok_q3lx490h
  • 它不起作用。 panic: interface conversion: interface {} is main.MyInt, not float64
  • 就像@TomSawyer 说它不起作用goplay.tools/snippet/-pNi3cRRDDS
【解决方案2】:

好的,我找到了

reflect.Value 有一个函数 Interface() 将其转换为 interface{}

【讨论】:

  • 将其转换为接口{}。我们如何将其转换为实际类型?
  • 这在 Go 中是不可能的,@Matt。如果没有不安全或手动的类型转换(至少在 Go 1 中),您就无法重新发明泛型。
  • concreteCat, _ := cat.Interface().(Cat) 对我有用,而不是 reflect.ValueOf(cat).Interface().(Cat)
  • @yountae.kang 我不确定您是否知道为什么会发生这种情况,但是无论哪种方式, cat.Interface().(Cat) 对您有用的原因是因为在上述用例中 cat是reflect.Value类型,不需要再转成reflect.Value类型。
【解决方案3】:

此函数根据需要自动转换类型。它根据结构名称和字段将配置文件值加载到一个简单的结构中:

import (
    "fmt"
    toml "github.com/pelletier/go-toml"
    "log"
    "os"
    "reflect"
)
func LoadConfig(configFileName string, configStruct interface{}) {
    defer func() {
        if r := recover(); r != nil {
            fmt.Println("LoadConfig.Recovered: ", r)
        }
    }()
    conf, err := toml.LoadFile(configFileName)
    if err == nil {
        v := reflect.ValueOf(configStruct)
        typeOfS := v.Elem().Type()
        sectionName := getTypeName(configStruct)
        for i := 0; i < v.Elem().NumField(); i++ {
            if v.Elem().Field(i).CanInterface() {
                kName := conf.Get(sectionName + "." + typeOfS.Field(i).Name)
                kValue := reflect.ValueOf(kName)
                if (kValue.IsValid()) {
                    v.Elem().Field(i).Set(kValue.Convert(typeOfS.Field(i).Type))
                }
            }
        }
    } else {
        fmt.Println("LoadConfig.Error: " + err.Error())
    }
}

【讨论】:

  • 这个问题应该被更新以反映这现在是正确的答案。
【解决方案4】:

似乎唯一的方法是执行类似于(下面的代码)的switch 语句(此外,类似注释行的内容虽然不起作用(:()),但会很好:

func valuesFromStruct (rawV interface{}) []interface{} {
    v := reflect.ValueOf(rawV)
    out := make([]interface{}, 0)
    for i := 0; i < v.NumField(); i += 1 {
        field := v.Field(i)
        fieldType := field.Type()
        // out = append(out, field.Interface().(reflect.PtrTo(fieldType)))
        switch (fieldType.Name()) {
        case "int64":
            out = append(out, field.Interface().(int64))
            break`enter code here`
        case "float64":
            out = append(out, field.Interface().(float64))
            break
        case "string":
            out = append(out, field.Interface().(string))
            break
        // And all your other types (here) ...
        default:
            out = append(out, field.Interface())
            break
        }
    }
    return out
}

干杯!

【讨论】:

    猜你喜欢
    • 2022-10-06
    • 2015-11-18
    • 1970-01-01
    • 1970-01-01
    • 2011-08-10
    • 2018-12-24
    • 1970-01-01
    • 1970-01-01
    • 2016-03-20
    相关资源
    最近更新 更多