Using reflect, how do you set the value of a struct field?

前端 未结 2 1413
醉话见心
醉话见心 2020-11-28 18:39

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          


        
相关标签:
2条回答
  • 2020-11-28 18:52

    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)
    }
    
    0 讨论(0)
  • 2020-11-28 19:14

    This seems to work:

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

    Prints:

    123
    321
    
    0 讨论(0)
提交回复
热议问题