【问题标题】:How to get underlying value from a reflect.Value in golang?如何从 golang 中的 reflect.Value 获取潜在价值?
【发布时间】:2013-08-08 03:09:34
【问题描述】:

所以我找到了一些代码来帮助我开始在 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() 方法只输出底层字符串。我想获取 int 并将其更改为字符串,但从 relfect 包文档中我没有立即看到它是如何完成的。

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

【问题讨论】:

  • reflect.Value 的 printf 将 (Go 1.5) 打印其实际值。见my answer below
  • @VonC 酷,感谢您的帮助,终于按照您的建议在 fmt 的帮助下获得了价值:goplay.space/#w98PfGoZHl8
  • 使用字段名称、类型、值和标签运行解决方案:goplay.space/#15XAsJBH5Sb
  • @Macilias 干得好。 (顺便说一句,我不知道 goplay.space:它看起来很方便)

标签: reflection go


【解决方案1】:

如何解析值的一个很好的例子是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

【讨论】:

  • 是的——我要发布我的答案,这里基本上是一样的。我想我尝试了很多次,但没有包括 reflect.Int 类型,认为 reflect.Int32 会涵盖这一点。一旦我添加了这个案例,尽管情况会更好。
  • 很高兴你提到它。原因是Int 类型依赖于平台(but at least 32 bit wide),其中Int32Int64 具有固定大小。
【解决方案2】:

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

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

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

【讨论】:

    【解决方案3】:

    使用 Go 1.5(2015 年 8 月)应该更容易做到这一点 请参阅review 8731commit 049b89d Rob Pike (robpike)

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

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

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

    这个 CL 通过对 fmt 包的微小更改来改善这种情况:当我们将 reflect.Value 视为参数时,我们将其视为我们在包内创建的 reflect.Value
    这意味着我们总是打印Value 的内容,就好像thatPrintf 的参数。

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

    【讨论】:

      【解决方案4】:

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

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

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

      【讨论】:

        猜你喜欢
        • 2015-12-29
        • 2021-01-21
        • 2021-09-13
        • 2017-03-20
        • 2022-11-14
        • 2017-07-30
        • 2018-06-14
        • 2019-04-17
        • 2022-01-24
        相关资源
        最近更新 更多