使用反射,你如何设置结构字段的值? [英] Using reflect, how do you set the value of a struct field?

查看:160
本文介绍了使用反射,你如何设置结构字段的值?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

使用 reflect 包处理结构字段有一段艰难的时间。特别是,还没有想出如何设置字段值。

 
类型t结构{fi int; fs string}
var rt = t {123,jblow}
var i64 int64 = 456



    $
  1. 获取字段i的名称 - 这似乎工作



    var field = reflect.TypeOf(r)。字段(i).Name


  2. 获取字段i的值为a)interface {},b)int - 工作



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



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

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

    反映.ValueOf(r).Field(i).SetInt(i64)



    panic :reflect.Value· SetInt使用未使用未报告的字段获得的值

    假定它不喜欢字段名称id和name,因此将其重命名为Id和Name



    a)这个假设是否正确?b)如果正确,认为没有必要,因为在相同的文件/包中
    p>

  4. settin g字段i的值 - 尝试两个(字段名大写) - 恐慌

    $ p $ reflect $ value(r).Field(i).SetInt (465)



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

    panic :reflect.Value·SetInt using unaddressable value


  5. ol>




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

    四。这样做:



    reflect.ValueOf(& r).Elem()。Field(i).SetInt(i64) $ b $ p

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

    解决方案

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



    Go json软件包编组并将JSON解组并封装到Go结构中。 b
    $ b




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

    Go 反映 包有 CanAddr 函数。

      func(v Value)CanAddr()bool 




    如果可以使用Addr获取值的
    地址,则CanAddr返回true 。
    这些值称为可寻址的。如果
    值是slice的
    元素,
    可寻址数组的元素,
    可寻址结构的字段或$ b $的结果b解引用指针。如果CanAddr
    返回false,调用Addr将导致
    恐慌。

    Go reflect 软件包有一个 CanSet 函数,如果 true ,意味着 CanAddr 也是 true



    < pre $ func(v Value)CanSet()bool




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


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

     包主

    导入(
    fmt
    反映


    func main(){
    type t struct {
    N int
    }
    var n = t {42 }
    // N开始
    fmt.Println(nN)
    //结构指针 - 可寻址
    ps:= reflect.ValueOf(& n)
    //结构
    s:= ps.Elem()$ b $如果s.Kind()== reflect.Struct {
    //导出字段
    f:= s.FieldByName(N )
    如果f.IsValid(){
    //一个值只有在
    //可寻址时才能被更改,并且不能被
    获得//使用未导出结构字段。
    if f.CanSet(){
    //改变N
    的值如果f.Kind()== reflect.Int {
    x:= int64(7)
    如果!f.OverflowInt(x){
    f.SetInt(x)
    }
    }
    }
    }
    }
    / / N结束
    fmt.Println(nN)
    }

    输出:
    42
    7

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

     









    $ main(){
    type t struct {
    N int
    }
    var n = t {42}
    fmt.PrintIn(nN)
    反映。 ValueOf(& n).Elem()。FieldByName(N).SetInt(7)
    fmt.Println(nN)
    }
    pre>

    having a rough time working with struct fields using reflect package. in particular, have not figured out how to set the field value.

    type t struct { fi int; fs string }
    var r t = t{ 123, "jblow" }
    var i64 int64 = 456
    

    1. getting Name of field i - this seems to work

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

    2. getting value of field i as a) interface{}, b) int - this seems to work

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

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

    3. setting value of field i - try one - panic

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

      panic: reflect.Value·SetInt using value obtained using unexported field

      assuming it did not like field names "id" and "name", so renamed to "Id" and "Name"

      a) is this assumption correct?

      b) if correct, thought not necessary since in same file / package

    4. setting value of field i - try two (with field names capitalized ) - panic

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

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

      panic: reflect.Value·SetInt using unaddressable value


    Instructions below by @peterSO are thorough and high quality

    Four. this works:

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

    he documents as well that the field names must be exportable (begin with capital letter)

    解决方案

    Go is available as open source code. A good way to learn about reflection is to see how the core Go developers use it. For example, the Go fmt and json packages. The package documentation has links to the source code files under the heading Package files.

    The Go json package marshals and unmarshals JSON from and to Go structures.


    Here's a step-by-step example which sets the value of a struct field while carefully avoiding errors.

    The Go reflect package has a CanAddr function.

    func (v Value) CanAddr() bool
    

    CanAddr returns true if the value's address can be obtained with Addr. Such values are called addressable. A value is addressable if it is an element of a slice, an element of an addressable array, a field of an addressable struct, or the result of dereferencing a pointer. If CanAddr returns false, calling Addr will panic.

    The Go reflect package has a CanSet function, which, if true, implies that CanAddr is also true.

    func (v Value) CanSet() bool
    

    CanSet returns true if the value of v can be changed. A Value can be changed only if it is addressable and was not obtained by the use of unexported struct fields. If CanSet returns false, calling Set or any type-specific setter (e.g., SetBool, SetInt64) will panic.

    We need to make sure we can Set the struct field. For example,

    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
    

    If we can be certain that all the error checks are unnecessary, the example simplifies to,

    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)
    }
    

    这篇关于使用反射,你如何设置结构字段的值?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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