使用reflect,如何设置struct字段的值?

cc *_*ung 94 reflection go go-reflect

粗略的时间使用reflect包使用struct字段.特别是,还没弄清楚如何设置字段值.

type t struct { fi int; fs string }
var r t = t{ 123, "jblow" }
var i64 int64 = 456
  1. 得到字段的名称我 - 这似乎工作

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

  2. 获得字段i的值作为a)接口{},b)int - 这似乎有效

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

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

  3. 设置字段的值i - 尝试一个 - 恐慌

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

    panic: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 )

    恐慌:反映.值/ SetInt使用不可寻址的值


@peterSO下面的说明是彻底和高质量的

四.这工作:

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

他还记录了字段名称必须是可导出的(以大写字母开头)

pet*_*rSO 134

Go可以作为开源代码使用.了解反射的一个好方法是看看核心Go开发人员如何使用它.例如,Go fmtjson包.包文档包含指向包文件下的源代码文件的链接.

Go json包对Go结构中的JSON进行编组和解组.


这是一个分步示例,它设置struct字段的值,同时小心避免错误.

Go reflect包有一个CanAddr功能.

func (v Value) CanAddr() bool
Run Code Online (Sandbox Code Playgroud)

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

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

func (v Value) CanSet() bool
Run Code Online (Sandbox Code Playgroud)

如果可以更改v的值,则CanSet返回true.仅当值可寻址且未通过使用未导出的结构域字段获得时,才能更改值.如果CanSet返回false,则调用Set或任何特定于类型的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(n.N)
    // 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(n.N)
}

Output:
42
7
Run Code Online (Sandbox Code Playgroud)

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

package main

import (
    "fmt"
    "reflect"
)

func main() {
    type t struct {
        N int
    }
    var n = t{42}
    fmt.Println(n.N)
    reflect.ValueOf(&n).Elem().FieldByName("N").SetInt(7)
    fmt.Println(n.N)
}
Run Code Online (Sandbox Code Playgroud)

  • 很棒的实际例子,这篇文章完全揭开它的神秘面纱http://golang.org/doc/articles/laws_of_reflection.html (5认同)
  • 放弃!在某个地方有一个答案,但json pkg的四个小时的工作并没有让我得到它.反映pkg,拉信息非常简单,但设置数据需要一些黑魔法,我很乐意在某处看到一个简单的例子! (4认同)
  • 优秀!如果你曾经在泰国,请让我给你一杯或两三杯啤酒!非常感谢你 (2认同)

Asg*_*eir 11

这似乎有效:

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()))
}
Run Code Online (Sandbox Code Playgroud)

打印:

123
321
Run Code Online (Sandbox Code Playgroud)