【问题标题】:Create instance of struct via reflection and set values通过反射创建结构实例并设置值
【发布时间】:2022-01-09 02:37:02
【问题描述】:

我想做什么

我尝试将instancestruct 传递给tags,包括tags 到func,创建一个新的instance,并在field 上设置value
在此之后我尝试序列化(JSON),但值为空

注意:我在 SO 上查找了大量关于通过反射设置值的文章,但似乎我错过了一些细节

结构定义

这部分定义了带有 json 和 xml 标签的结构

type Person struct {
    Name string `json:"Name" xml:"Person>FullName"`
    Age  int    `json:"Age" xml:"Person>Age"`
}

创建实例(+包装成空接口)

之后我创建了一个实例并将其存储在 interface{} 中 - 为什么?因为在我的生产代码中,这些东西将在func 中完成,它接受interface{}

var iFace interface{} = Person{
        Name: "Test",
        Age:  666,
    }

创建结构的新实例并通过反射设置值

iFaceType := reflect.TypeOf(iFace)
    item := reflect.New(iFaceType)
    s := item.Elem()
    if s.Kind() == reflect.Struct {
        fName := s.FieldByName("Name")
        if fName.IsValid() {
            // A Value can be changed only if it is
            // addressable and was not obtained by
            // the use of unexported struct fields.
            if fName.CanSet() {
                // change value of N
                switch fName.Kind() {
                case reflect.String:
                    fName.SetString("reflectedNameValue")
                    fmt.Println("Name was set to reflectedNameValue")
                }
            }
        }
        fAge := s.FieldByName("Age")
        if fAge.IsValid() {
            // A Value can be changed only if it is
            // addressable and was not obtained by
            // the use of unexported struct fields.
            if fAge.CanSet() {
                // change value of N
                switch fAge.Kind() {
                case reflect.Int:
                    x := int64(42)
                    if !fAge.OverflowInt(x) {
                        fAge.SetInt(x)
                        fmt.Println("Age was set to", x)
                    }
                }
            }
        }
    }

问题

我做错了什么?
在生产代码中,我用数据填充多个副本并将其添加到 slice...
但这只有在 json tags 保持在原位并且东西以相同的方式序列化时才有意义。

播放代码示例

package main

import (
    "encoding/json"
    "fmt"
    "reflect"
)

func main() {
    type Person struct {
        Name string `json:"Name" xml:"Person>FullName"`
        Age  int    `json:"Age" xml:"Person>Age"`
    }

    var iFace interface{} = Person{
        Name: "Test",
        Age:  666,
    }
    fmt.Println("normal: \n" + JSONify(iFace))
    iFaceType := reflect.TypeOf(iFace)
    item := reflect.New(iFaceType)
    s := item.Elem()
    if s.Kind() == reflect.Struct {
        fName := s.FieldByName("Name")
        if fName.IsValid() {
            // A Value can be changed only if it is
            // addressable and was not obtained by
            // the use of unexported struct fields.
            if fName.CanSet() {
                // change value of N
                switch fName.Kind() {
                case reflect.String:
                    fName.SetString("reflectedNameValue")
                    fmt.Println("Name was set to reflectedNameValue")
                }
            }
        }
        fAge := s.FieldByName("Age")
        if fAge.IsValid() {
            // A Value can be changed only if it is
            // addressable and was not obtained by
            // the use of unexported struct fields.
            if fAge.CanSet() {
                // change value of N
                switch fAge.Kind() {
                case reflect.Int:
                    x := int64(42)
                    if !fAge.OverflowInt(x) {
                        fAge.SetInt(x)
                        fmt.Println("Age was set to", x)
                    }
                }
            }
        }
    }
    fmt.Println("reflected: \n" + JSONify(item))
}

func JSONify(v interface{}) string {
    var bytes []byte
    bytes, _ = json.MarshalIndent(v, "", "\t")
    return string(bytes)
}

【问题讨论】:

    标签: json go struct reflection


    【解决方案1】:

    您的itemreflect.Value 类型。您必须调用Value.Interface() 来获取其中包含的值:

    fmt.Println("reflected: \n" + JSONify(item.Interface()))
    

    通过此更改,输出将是(在Go Playground 上尝试):

    normal: 
    {
        "Name": "Test",
        "Age": 666
    }
    Name was set to reflectedNameValue
    Age was set to 42
    reflected: 
    {
        "Name": "reflectedNameValue",
        "Age": 42
    }
    

    reflect.Value 本身也是一个结构,但显然尝试编组它与编组 Person 结构值不同。 reflect.Value 没有实现将打包的数据编组为 JSON。

    【讨论】:

    • 非常感谢 - 我的完整代码正在处理这个小改动。一个小错误,花了我几个小时......
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-09-06
    • 2021-03-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多