簡體   English   中英

通過反射創建結構實例並設置值

[英]Create instance of struct via reflection and set values

我想做什么

我嘗試將structinstance (包括json tag )傳遞給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 tag保持在適當位置並且東西以相同的方式序列化時才有意義。

播放代碼示例

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

您的item是類型reflect.Value 您必須調用Value.Interface()來獲取包含在其中的值:

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

通過此更改,output 將是(在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。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM