英文:
How to flatten a Struct with embedded structs to json
问题
给定以下结构类型,StructA
和StructB
嵌入在CompleteStruct
中:
type StructA struct {
A int `json:"a_a"`
B int `json:"a_b"`
C int `json:"a_c"`
}
type StructB struct {
A int `json:"b_a"`
B int `json:"b_b"`
}
type CompleteStruct struct {
Name string `json:"name"`
StructA
StructB
}
还有一个新的结构体s
:
s := CompleteStruct{Name: "Example",
StructA: StructA{
A: 1,
B: 2,
C: 3,
},
StructB: StructB{
A: 4,
B: 5,
},
}
你想要将s
转换为以下JSON格式:
[
{
"name": "Example",
"field": "a_a",
"value": 1
},
{
"name": "Example",
"field": "a_b",
"value": 2
},
{
"name": "Example",
"field": "a_c",
"value": 3
},
{
"name": "Example",
"field": "b_a",
"value": 4
},
{
"name": "Example",
"field": "b_b",
"value": 5
}
]
注意:实际上,CompleteStruct
将包含10个或更多嵌入的结构体,每个嵌入的结构体将包含10个或更多字段。因此,我希望找到一种不需要逐个键入每个字段的解决方案,我认为这将需要使用反射。
英文:
Given the following struct types, StructA
and StructB
that are embedded in CompleteStruct
type StructA struct {
A int `json:"a_a"`
B int `json:"a_b"`
C int `json:"a_c"`
}
type StructB struct {
A int `json:"b_a"`
B int `json:"b_b"`
}
type CompleteStruct struct {
Name string `json:"name"`
StructA
StructB
}
And s
which is a new struct.
s := CompleteStruct{Name: "Example",
StructA: StructA{
A: 1,
B: 2,
C: 3,
},
StructB: StructB{
A: 4,
B: 5,
},
}
How do you transform s
to the following json.
[
{
"name": "Example",
"field": "a_a",
"value": 1
},
{
"name": "Example",
"field": "a_b",
"value": 2
},
{
"name": "Example",
"field": "a_c",
"value": 3
},
{
"name": "Example",
"field": "b_a",
"value": 4
},
{
"name": "Example",
"field": "b_b",
"value": 5
}
]
Note: In reality, CompleteStruct
will contain 10 or more embedded structs and each embedded struct will contain 10 or more fields. So I would like a solution that does not require typing each field out individually, I assume this will require using reflection
答案1
得分: 2
你不能没有反射来解决这个问题。这是一个简单的例子:
func (u *CompleteStruct) MarshalJSON() ([]byte, error) {
type Result struct {
Name string `json:"name"`
Field string `json:"field"`
Value any `json:"value"`
}
var res []Result
val := reflect.ValueOf(u).Elem()
for i := 0; i < val.NumField(); i++ {
field := val.Field(i)
switch field.Kind() {
case reflect.Struct:
for i := 0; i < field.NumField(); i++ {
tp := field.Type().Field(i)
field := field.Field(i)
res = append(res, Result{
Name: u.Name,
Field: tp.Tag.Get("json"),
Value: field.Interface(),
})
}
}
}
return json.Marshal(res)
}
英文:
You can't solve it without reflection. Simple example:
func (u *CompleteStruct) MarshalJSON() ([]byte, error) {
type Result struct {
Name string `json:"name"`
Field string `json:"field"`
Value any `json:"value"`
}
var res []Result
val := reflect.ValueOf(u).Elem()
for i := 0; i < val.NumField(); i++ {
field := val.Field(i)
switch field.Kind() {
case reflect.Struct:
for i := 0; i < field.NumField(); i++ {
tp := field.Type().Field(i)
field := field.Field(i)
res = append(res, Result{
Name: u.Name,
Field: tp.Tag.Get("json"),
Value: field.Interface(),
})
}
}
}
return json.Marshal(res)
}
<kbd>PLAYGROUND</kbd>
答案2
得分: 0
这应该给你想要的结构:
package main
import (
"encoding/json"
"os"
"reflect"
)
type StructA struct {
A int `json:"a_a"`
B int `json:"a_b"`
C int `json:"a_c"`
}
type StructB struct {
A int `json:"b_a"`
B int `json:"b_b"`
}
type CompleteStruct struct {
Name string `json:"name"`
StructA StructA
StructB StructB
}
func main() {
s := CompleteStruct{Name: "Example",
StructA: StructA{
A: 1,
B: 2,
C: 3,
},
StructB: StructB{
A: 4,
B: 5,
},
}
flat(s)
json.NewEncoder(os.Stdout).Encode(results)
}
type resp struct {
Name string `json:"name"`
Field string `json:"field"`
Value interface{} `json:"value"`
}
var globalName string
var results []resp
func flat(s interface{}) {
st := reflect.TypeOf(s)
for i := 0; i < st.NumField(); i++ {
field := st.Field(i)
if field.Type.Kind() == reflect.Struct {
flat(reflect.ValueOf(s).Field(i).Interface())
} else {
name := field.Tag.Get("json")
if name == "name" {
globalName = reflect.ValueOf(s).Field(i).String()
continue
}
results = append(results, resp{Name: globalName, Field: name, Value: reflect.ValueOf(s).Field(i).Interface()})
}
}
}
go run ./main.go | jq '.'
英文:
This should give you the structure you want:
package main
import (
"encoding/json"
"os"
"reflect"
)
type StructA struct {
A int `json:"a_a"`
B int `json:"a_b"`
C int `json:"a_c"`
}
type StructB struct {
A int `json:"b_a"`
B int `json:"b_b"`
}
type CompleteStruct struct {
Name string `json:"name"`
StructA
StructB
}
func main() {
s := CompleteStruct{Name: "Example",
StructA: StructA{
A: 1,
B: 2,
C: 3,
},
StructB: StructB{
A: 4,
B: 5,
},
}
flat(s)
json.NewEncoder(os.Stdout).Encode(results)
}
type resp struct {
Name string `json:"name"`
Field string `json:"field"`
Value any `json:"value"`
}
var globalName string
var results []resp
func flat(s interface{}) {
st := reflect.TypeOf(s)
for i := 0; i < st.NumField(); i++ {
field := st.Field(i)
if field.Type.Kind() == reflect.Struct {
flat(reflect.ValueOf(s).Field(i).Interface())
} else {
name := field.Tag.Get("json")
if name == "name" {
globalName = reflect.ValueOf(s).Field(i).String()
continue
}
results = append(results, resp{Name: globalName, Field: name, Value: reflect.ValueOf(s).Field(i).Interface()})
}
}
}
go run ./main.go | jq '.'
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论