type Client struct {
    Id                int
    Age               int
    PrimaryContact    Contact
    Name              string
}

type Contact struct {
    Id        int
    ClientId  int
    IsPrimary bool
    Email     string
}

以上是示例代码;我想要实现的是以下内容:
- 使用反射循环遍历所有客户端结构字段
- 使用反射为每个“原始”字段设置默认值
- 对于每个结构字段使用递归来应用上述步骤

问题是,当内省(introspection) PrimaryContact 字段时,当我尝试为其任何字段设置值时,我最终会出现以下 panic :



如果我没记错的话,原因是 PrimaryContact 是按值而不是按引用传递的,所以当我在其任何字段上调用 ​​Set 方法时,它会更改副本上的字段值,而不是实际参数上的值。我怎样才能克服这个问题?如何使用反射通过引用将 PrimaryContact 字段传递给我的方法?

最佳答案

我认为这是练习反射(reflection)的有趣练习。

两个指针:

  • 为了设置结构体的字段值,您必须将其作为指针传递
  • 要获取结构体字段的指针值,请使用 Value.Addr()

  • 工作解决方案:
    package main
    
    import (
        "fmt"
        "reflect"
        "errors"
    )
    
    type Client struct {
        Id                int
        Age               int
        PrimaryContact    Contact
        Name              string
    }
    
    type Contact struct {
        Id        int
        ClientId  int
        IsPrimary bool
        Email     string
    }
    
    func SetDefault(s interface{}) error {
        return setDefaultValue(reflect.ValueOf(s))
    }
    
    func setDefaultValue(v reflect.Value) error {
    
        if v.Kind() != reflect.Ptr {
            return errors.New("Not a pointer value")
        }
    
        v = reflect.Indirect(v)
        switch v.Kind() {
            case reflect.Int:
                v.SetInt(42)
            case reflect.String:
                v.SetString("Foo")
            case reflect.Bool:
                v.SetBool(true)
            case reflect.Struct:
                // Iterate over the struct fields
                for i := 0; i < v.NumField(); i++ {
                    err := setDefaultValue(v.Field(i).Addr())
                    if err != nil {
                        return err
                    }
                }
    
            default:
                return errors.New("Unsupported kind: " + v.Kind().String())
    
        }
    
        return nil
    }
    
    
    func main() {
        a := Client{}
        err := SetDefault(&a)
        if err != nil {
            fmt.Println("Error: ", err)
        } else {
            fmt.Printf("%+v\n", a)
        }
    }
    

    输出:
    {Id:42 Age:42 PrimaryContact:{Id:42 ClientId:42 IsPrimary:true Email:Foo} Name:Foo}
    

    游乐场: http://play.golang.org/p/-Mpnb7o4vl

    关于reflection - 通过反射传递引用嵌套结构,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/25047424/

    10-13 09:13