40

So I found some code that help me get started with reflection in Go (golang), but I'm having trouble getting a the underlying value so that I can basically create a map[string]string from a struct and it's fields.

Eventually, I'd like to make the result into a map[string]interface{}, but this one issue is kind of blocking me.

The code I have at the moment:

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

The output from running the code:

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

From what I understand the output for FirstName and LastName are actual reflect.Value objects but for strings the String() method on value just outputs the underlying String. I'd like to either get the int and change it into a string, but from the relfect package documentation I'm not immediately seeing how that's done.

Soo.... How do I get the underlying value from a reflect.Value in golang?

4

4 回答 4

24

如何解析值的一个很好的例子是fmt包。请参阅此代码

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

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...
}

基本上你需要检查所有可用的 Kinds

于 2013-08-07T17:14:16.777 回答
5

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

一旦您从val.Interface()//获得值val.String()val.Int() 您就可以根据需要转换您的值。你使用什么将取决于reflect.Kind. 要转换int到/从string您需要使用strconv包。

encoding/json和包已经完成了这种encoding/xml工作。源代码提供了一些很好的例子。copyValue例如,看看encoding/xml/read.go和encoding/xml / marshal.gomarshalSimple

于 2013-08-06T23:14:41.870 回答
2

使用 Go 1.5(2015 年 8 月)应该更容易做到这一点,请参阅Rob Pike ( )评论 8731提交 049b89drobpike

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

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

当 areflect.Value被传递给Printf(等)时,fmt调用了该String方法,该方法不透露其内容。
要获取内容,可以调用,但如果不导出或以其他方式禁止Value.Interface(),则这是非法的。Value

这个 CL 通过对包的一个微不足道的改变来改善这种情况fmt:当我们将 areflect.Value作为参数时,我们将其视为我们reflect.Value在包中创建的 a。
这意味着我们总是打印 的内容,Value就好像是 的参数一样Printf

这可以说是一个突破性的变化,但我认为这是一个真正的改进,并且不比我们对这个包的格式化输出所做的许多其他调整更大。

于 2015-04-16T08:06:32.533 回答
1

另一个简单的解决方案是,

flavorName = fmt.Sprintf("%v",strct)

fmt.Sprintf() ”将返回可以存储在变量中的值。

于 2020-02-03T11:32:40.363 回答