通过反射创建结构实例并设置值
Create instance of struct via reflection and set values
我想做什么
我尝试将 struct
的 instance
- 包括 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
. You have to call 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。
我想做什么
我尝试将 struct
的 instance
- 包括 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
. You have to call 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。