首页 文章

如何从golang中的reflect.Value获取基础值?

提问于
浏览
28

所以我找到了一些代码来帮助我开始使用Go(golang)中的反射,但是我在获取基础值时遇到了麻烦,因此我基本上可以从结构和它的字段创建一个 map[string]string .

最后,我想把结果变成 map[string]interface{} ,但是这个问题有点阻碍了我 .

我现在的代码:

package main

import (
    "fmt"
    "reflect"
)

type Foo struct {
    FirstName string `tag_name:"tag 1"`
    LastName  string `tag_name:"tag 2"`
    Age       int  `tag_name:"tag 3"`
}

func inspect(f interface{}) map[string]string {

    m := make(map[string]string)
    val := reflect.ValueOf(f).Elem()

    for i := 0; i < val.NumField(); i++ {
        valueField := val.Field(i)
        typeField := val.Type().Field(i)

        f := valueField.Interface()
        val := reflect.ValueOf(f)
        m[typeField.Name] = val.String()
    }

    return m
}

func dump(m map[string]string) {

    for k, v := range m {
        fmt.Printf("%s : %s\n", k, v)
    }
}

func main() {
    f := &Foo{
        FirstName: "Drew",
        LastName:  "Olson",
        Age:       30,
    }

    a := inspect(f)

    dump(a)
}

运行代码的输出:

FirstName : Drew
LastName : Olson
Age : <int Value>

根据我的理解,FirstName和LastName的输出是实际的reflect.Value对象,但对于字符串,值上的String()方法只输出底层的String . 我想要获取int并将其更改为字符串,但是从relfect包文档中我不会立即看到它是如何完成的 .

Soo ....如何从golang中的reflect.Value中获取基础值?

3 回答

  • 14

    fmt 包是一个如何解析值的好例子 . 见this code .

    使用上面提到的代码来匹配您的问题将如下所示:

    switch val.Kind() {
    case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
        m[typeField.Name] = strconv.FormatInt(val.Int(), 10)
    case reflect.String:
        m[typeField.Name] = val.String()    
    // etc...
    }
    

    基本上你需要检查所有available Kinds .

  • 2

    看起来你走在正确的轨道上 . 我在代码中看到的问题是它对值进行了假设,这意味着何时调用 Elem() 以及多少次(以解析指针) . 为了了解这一点,您需要查看 reflect.Kind . 值是 reflect.Ptr ?然后使用 Elem() .

    val.Interface() / val.String() / val.Int() 获得值后,您可以根据需要转换值 . 你使用的将取决于 reflect.Kind . 要将 int 转换为/从 string 转换,您需要使用 strconv 包 .

    encoding/jsonencoding/xml 包已经完成了这种工作 . 源代码提供了一些很好的例子 . 例如,请查看encoding/xml/read.go中的 copyValueencoding/xml/marshal.go中的 marshalSimple .

  • 3

    这应该更容易用Go 1.5(2015年8月)查看review 8731commit 049b89dRob Pike (robpike)

    fmt:特别对待reflect.Value - 作为它所持有的 Value

    这将允许您打印 Reflect.Value() 参数的实际值:

    当一个reflect.Value传递给Printf(等)时,fmt调用String方法,该方法不公开其内容 . 要获取内容,可以调用Value.Interface(),但如果未导出或禁止Value,则这是非法的 . 这个CL通过对fmt包进行微不足道的改变来改善这种情况:当我们看到一个reflect.Value作为参数时,我们将它视为处理我们在包内进行的reflect.Value . 这意味着我们总是打印Value的内容,就好像这是Printf的参数 . 这可以说是一个突破性的变化,但我认为这是一个真正的改进,并没有比我们对这个包的格式化输出所做的许多其他调整更大的突破 .

相关问题