在Go中通过反射为结构成员赋值 [英] Assigning a value to struct member through reflection in Go

查看:152
本文介绍了在Go中通过反射为结构成员赋值的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个结构v与成员A,B,C字符串。使用反射,我可以得到字段的名称和它们的值:

  typ:= v.Type()
代表i:= 0;我< v.NumField(); i ++ {
//获得一个StructField
fi:= typ.Field(i)
fieldname:= fi.Name
fmt.Println(fieldname)
val := fmt.Sprintf(%v,v.Field(i).Interface())
}

因为我有名字,并且可以获得OUT值,我可以为这些字段分配新值吗?我希望做到:
$ b $ pre $ v.Field(fieldname).Interface()=新值

但这显然不起作用。如果你只知道字段的名称,是否可以将一个值赋给一个结构?



实际上,我试图从将[string] string 映射到结构中的相应字段,其中结构和映射定义可随时间扩展变化,并且映射可包含比结构更多或更少的值。我曾考虑过使用JSON来做这件事,但这种做法让我感到有点冷,因为使用反射来获得差不多是多么容易!

谢谢,

解决方案

是的,这是可能的。





由于您想要访问和修改变量(或字段)的值,因此您需要使用 reflect.Value 类型而不是 reflect.Type 。您可以通过 reflect.ValueOf() 。同样为了用反射来修改它,你需要传递 struct 的地址(指针)或者你想修改的值(否则你只能读取它,而不能修改它)。



但您不想修改地址/指针,而是修改指向的值,因此您必须导航从 Value 指针指向指向变量(struct)的 Value ,这就是 Value.Elem() 是用于。它看起来像这样: reflect.ValueOf(& s).Elem()



具有 <$ c的struct字段的code> Value $ c> Value.FieldByName() 方法,因为我们将指针的地址传递给 ValueOf()函数be settable


$ b 代码

一旦你了解它,代码就比引言简单得多。您也可以在去游乐场试试它:

  var s struct {
A,B,C string
}
sA,sB,sC =a1,b2, c3

fmt.Println(Before:,s)

v:= reflect.ValueOf(& s).Elem()

v.FieldByName(A).SetString(2a)
v.FieldByName(B).SetString(2b)
v.FieldByName(C).SetString (2c)

fmt.Println(After:,s)

//使用地图:
m:= map [string] string { A:ma,B:mb,C:mc}
for mk,mv:= range m {
v.FieldByName(mk).SetString mv)
}

fmt.Println(From Map:,s)

输出:

 之前:{a1 b2 c3} 
之后:{2a 2b 2c}
来自地图:{ma mb mc}

我推荐阅读这篇博文来学习Go中反射的基础知识:

反思的法则


I have a struct v with members A, B, C string. Using reflection, I can get the names of the fields and their values:

typ := v.Type()
for i := 0; i < v.NumField(); i++ {
    // gets us a StructField
    fi := typ.Field(i)
    fieldname := fi.Name
    fmt.Println(fieldname)
    val := fmt.Sprintf("%v", v.Field(i).Interface())
 }

since I have the name, and can get the value OUT, can I assign new values to the fields? I would like to do essentially:

v.Field(fieldname).Interface() = "new value"

but that obviously doesn't work. Is it possible to assign a value into a struct if you only know the name of the field?

In practice, I'm trying to assign values from a map[string]string to corresponding fields in a struct, where the struct and map definitions may expand of change over time, and the map may contain more, or less, values than the struct. I've considered doing it w/JSON, but that approach leaves me a little cold, seeing as how easy it was to use reflection to get "almost" there!

Thanks, Ken

解决方案

Yes, it is possible.

Introduction

Since you want to access and modify the value of a variable (or field), you need to use the reflect.Value type instead of reflect.Type. You can acquire it with reflect.ValueOf(). Also in order to modify it with reflection, you need to pass the address (a pointer) of the struct or value you want to modify (else you could only read it but not modify it).

But you don't want to modify the address/pointer but the pointed value, so you have to "navigate" from the Value of the pointer to the Value of the pointed variable (struct), this is what Value.Elem() is for. It looks like this: reflect.ValueOf(&s).Elem()

You can get the Value of a struct field with the Value.FieldByName() method, which since we passed the address of the pointer to the ValueOf() function will be settable.

The Code

The code is much simpler than the introduction once you understand it. You can also try it on the Go Playground:

var s struct {
    A, B, C string
}
s.A, s.B, s.C = "a1", "b2", "c3"

fmt.Println("Before:  ", s)

v := reflect.ValueOf(&s).Elem()

v.FieldByName("A").SetString("2a")
v.FieldByName("B").SetString("2b")
v.FieldByName("C").SetString("2c")

fmt.Println("After:   ", s)

// Using a map:
m := map[string]string{"A": "ma", "B": "mb", "C": "mc"}
for mk, mv := range m {
    v.FieldByName(mk).SetString(mv)
}

fmt.Println("From Map:", s)

Output:

Before:   {a1 b2 c3}
After:    {2a 2b 2c}
From Map: {ma mb mc}

I recommend to read this blog post to learn the basics of the reflection in Go:

The Laws of Reflection

这篇关于在Go中通过反射为结构成员赋值的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆