使用reflection,你如何设置一个struct字段的值?

有一个艰难的时间使用reflect包使用struct字段。 特别是还没有想出如何设置字段值。

键入t struct {fi int;  fs string}
 var rt = t {123,“jblow”}
 var i64 int64 = 456
  1. 得到领域的名字我 – 这似乎工作

    var field = reflect.TypeOf(r).Field(i).Name

  2. 获得领域我的价值作为一个)interface {},b)int – 这似乎工作

    var iface interface{} = reflect.ValueOf(r).Field(i).Interface()

    var i int = int(reflect.ValueOf(r).Field(i).Int())

  3. 设置领域的价值 – 尝试一个恐慌

    reflect.ValueOf(r).Field(i).SetInt( i64 )

    恐慌 :reflect.Value·SetInt使用取得的值使用未导出的字段

    假设它不喜欢字段名称“id”和“name”,所以改名为“Id”和“Name”

    a)这个假设是否正确?

    b)如果正确,认为没有必要,因为在相同的文件/包

  4. 设置字段i的值 – 尝试两个(字段名称大写) – 恐慌

    reflect.ValueOf(r).Field(i).SetInt( 465 )

    reflect.ValueOf(r).Field(i).SetInt( i64 )

    恐慌 :reflect.Value·SetInt使用unaddressable值


以下说明@peterSO是彻底的,高质量

四。 这工作:

reflect.ValueOf(&r).Elem().Field(i).SetInt( i64 )

他还logging了域名必须是可导出的(以大写字母开头)

Go以开源代码的forms提供 。 了解反思的一个好方法是看看核心Go开发人员如何使用它。 例如,Go fmt和json软件包。 软件包文档包含指向软件包文件标题下的源代码文件的链接。

Go json包封送和解组JSON来自Go结构。


这是一个循序渐进的例子,它可以设置一个struct字段的值,同时小心避免错误。

Go reflect包有一个CanAddr函数。

 func (v Value) CanAddr() bool 

如果可以使用Addr获取值的地址,则CanAddr返回true。 这些值被称为可寻址的。 如果值是切片的元素,可寻址数组的元素,可寻址结构的字段或解引用指针的结果,则该值是可寻址的。 如果CanAddr返回false,调用Addr将会发生混乱。

Go reflect包有一个CanSet函数,如果为true ,则暗示CanAddr也是true

 func (v Value) CanSet() bool 

如果v的值可以改变,CanSet返回true。 值只有在可寻址的情况下才能被改变,并且不能通过使用未导出的结构字段来获得。 如果CanSet返回false,则调用Set或任何types特定的setter(例如,SetBool,SetInt64)将会发生混乱。

我们需要确保我们可以Set struct字段。 例如,

 package main import ( "fmt" "reflect" ) func main() { type t struct { N int } var n = t{42} // N at start fmt.Println(nN) // pointer to struct - addressable ps := reflect.ValueOf(&n) // struct s := ps.Elem() if s.Kind() == reflect.Struct { // exported field f := s.FieldByName("N") if f.IsValid() { // A Value can be changed only if it is // addressable and was not obtained by // the use of unexported struct fields. if f.CanSet() { // change value of N if f.Kind() == reflect.Int { x := int64(7) if !f.OverflowInt(x) { f.SetInt(x) } } } } } // N at end fmt.Println(nN) } Output: 42 7 

如果我们可以确定所有的错误检查是不必要的,那么这个例子简化为:

 package main import ( "fmt" "reflect" ) func main() { type t struct { N int } var n = t{42} fmt.Println(nN) reflect.ValueOf(&n).Elem().FieldByName("N").SetInt(7) fmt.Println(nN) } 

这似乎工作:

 package main import ( "fmt" "reflect" ) type Foo struct { Number int Text string } func main() { foo := Foo{123, "Hello"} fmt.Println(int(reflect.ValueOf(foo).Field(0).Int())) reflect.ValueOf(&foo).Elem().Field(0).SetInt(321) fmt.Println(int(reflect.ValueOf(foo).Field(0).Int())) } 

打印:

 123 321