dongyinting3179 2011-06-18 09:24
浏览 82
已采纳

使用反射,如何设置结构字段的值?

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)

  • 写回答

2条回答 默认 最新

  • druzuz321103 2011-06-18 14:29
    关注

    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)
    }
    
    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论
查看更多回答(1条)

报告相同问题?

悬赏问题

  • ¥15 请问有人会紧聚焦相关的matlab知识嘛?
  • ¥50 yalmip+Gurobi
  • ¥20 win10修改放大文本以及缩放与布局后蓝屏无法正常进入桌面
  • ¥15 itunes恢复数据最后一步发生错误
  • ¥15 关于#windows#的问题:2024年5月15日的win11更新后资源管理器没有地址栏了顶部的地址栏和文件搜索都消失了
  • ¥100 H5网页如何调用微信扫一扫功能?
  • ¥15 讲解电路图,付费求解
  • ¥15 有偿请教计算电磁学的问题涉及到空间中时域UTD和FDTD算法结合的
  • ¥15 three.js添加后处理以后模型锯齿化严重
  • ¥15 vite打包后,页面出现h.createElement is not a function,但本地运行正常