如何将嵌入结构的结构展平为 json

Eri*_*ric 5 struct go

给定以下结构类型,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
}

Run Code Online (Sandbox Code Playgroud)

这s是一个新的结构。

s := CompleteStruct{Name: "Example",
    StructA: StructA{
        A: 1, 
        B: 2, 
        C: 3,
    },
    StructB: StructB{
        A: 4,
        B: 5,
    },
}
Run Code Online (Sandbox Code Playgroud)

如何转化s为下面的json.

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
}

Run Code Online (Sandbox Code Playgroud)

注意:实际上,CompleteStruct将包含 10 个或更多嵌入结构,每个嵌入结构将包含 10 个或更多字段。所以我想要一个不需要单独输入每个字段的解决方案,我认为这需要使用反射

Mih*_*hai 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
    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()})
        }
    }
}
Run Code Online (Sandbox Code Playgroud)
go run ./main.go | jq '.'
Run Code Online (Sandbox Code Playgroud)

去游乐场