英文:
How to get underlying value from a reflect.Value in golang?
问题
我找到了一些帮助我开始在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并将其更改为字符串,但是从reflect包的文档中,我并没有立即看到如何实现这一点。
那么...如何从reflect.Value中获取底层值呢?
英文:
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?
答案1
得分: 30
一个很好的解析值的示例是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()
// 等等...
}
基本上,你需要检查所有可用的类型。
英文:
A good example of how to parse values is the fmt
package. See this code.
Using the mentioned code to match your problem would look like this:
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...
}
Basically you need to check for all available Kinds.
答案2
得分: 6
看起来你在正确的方向上。我看到你的代码存在一个问题,它对值做了一些假设,也就是说你何时调用Elem()
以及调用多少次(用于解析指针)。为了知道这一点,你需要查看reflect.Kind
。值是reflect.Ptr
吗?那么就使用Elem()
。
一旦你从val.Interface()
/ val.String()
/ val.Int()
中获取到值,你可以根据需要进行转换。你使用的方法将取决于reflect.Kind
。要将int
转换为string
或从string
转换为int
,你需要使用strconv
包。
encoding/json
和encoding/xml
包已经提供了这种类型的工作。源代码中提供了一些很好的示例。例如,看一下encoding/xml/read.go中的copyValue
和encoding/xml/marshal.go中的marshalSimple
。
英文:
It looks like you're on the right track. The problem I see with your code is it makes assumptions about the values, meaning when do you call Elem()
and how many times (to resolve pointers). In order to know this you need to look at the reflect.Kind
. Is the value a reflect.Ptr
? Then use Elem()
.
Once you have the value from val.Interface()
/ val.String()
/ val.Int()
you can convert your values as needed. What you use is going to depend on reflect.Kind
. To convert an int
to/from string
you need to use the strconv
package.
The encoding/json
and encoding/xml
packages do this kind of work already. The source code provides some great examples. For example, take a look at copyValue
in encoding/xml/read.go and marshalSimple
in encoding/xml/marshal.go.
答案3
得分: 4
这在 Go 1.5(2015年8月)中应该更容易实现。
参见 review 8731 和 commit 049b89d 由 Rob Pike (robpike
) 提交的更改:
> ## fmt
: 特殊处理 reflect.Value
- 作为其所持有的值
这将允许您打印 Reflect.Value()
参数的实际值:
> 当将 reflect.Value
传递给 Printf
(等等)时,fmt
调用了 String
方法,该方法不会透露其内容。
要获取内容,可以调用 Value.Interface()
,但如果 Value
未导出或受其他限制,则此操作是非法的。
> 这个更改通过对 fmt
包进行微小的更改来改善情况:当我们将 reflect.Value
视为参数时,我们将其与在包内创建的 reflect.Value
完全相同对待。
这意味着我们始终打印 Value
的内容,就好像 那个 是传递给 Printf
的参数一样。
> 这可能是一个破坏性的更改,但我认为这是一个真正的改进,不会比我们对该包的格式化输出进行的许多其他微调更破坏。
英文:
This should be easier to do with Go 1.5 (August 2015)
See review 8731 and commit 049b89d by Rob Pike (robpike
):
> ## fmt
: treat reflect.Value
specially - as the value it holds
This would allow you to print the actual value of a Reflect.Value()
argument:
> When a reflect.Value
is passed to Printf
(etc.), fmt
called the String
method, which does not disclose its contents.
To get the contents, one could call Value.Interface()
, but that is illegal
if the Value
is not exported or otherwise forbidden.
> This CL improves the situation with a trivial change to the fmt
package: when we see a reflect.Value
as an argument, we treat it exactly as we treat a reflect.Value
we make inside the package.
This means that we always print the contents of the Value
as if that was the argument to Printf
.
> This is arguably a breaking change but I think it is a genuine improvement and no greater a break than many other tweaks we have made to formatted output from this package.
答案4
得分: 2
另一个简单的解决方案可以是,
flavorName = fmt.Sprintf("%v", strct)
"fmt.Sprintf()"将返回可以存储在变量中的值。
英文:
Another simple solution can be ,
flavorName = fmt.Sprintf("%v",strct)
" fmt.Sprintf() " will return the value which can be stored in a variable.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论