You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Golang如何基于任意层级嵌套结构体递归构建嵌套JSON对象

代码问题定位

你当前实现无法生成正确嵌套结构的核心原因有4个:

  • 递归函数返回值为空:buildRecursiveFunction最后返回的是初始化的空temp map,没有存入遍历生成的字段数组,递归拿到的子结构始终是空值。
  • 嵌套字段类型赋值错误:遇到指针类型的结构体字段时,你给字段Type赋值为"ptr",但目标输出中嵌套结构体的类型固定为"struct",指针只是类型的引用方式,不是最终输出的类型标识。
  • 根节点结构缺失:现有逻辑直接遍历字段,没有生成最外层包含结构体名、Fields数组的顶层结构,和目标输出格式不匹配。
  • 子结构赋值逻辑错误:遇到指针指向的结构体时,你直接把递归返回的整个map塞给当前字段的Fields,但递归返回的map是子结构体的完整描述(含子结构体名、子结构体Fields),实际只需要取子结构的Fields数组赋值即可。
修正后完整实现
package main

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

// 示例结构体定义
type Data struct {
	ID    string
	Name  string
	Types *Details
}

type Details struct {
	Customer  int32
	Countries int32
}

func check(e error) {
	if e != nil {
		panic(e)
	}
}

// 递归构建结构体的schema描述,入参必须是struct类型
func buildStructSchema(t reflect.Type) map[string]interface{} {
	schema := make(map[string]interface{})
	schema["Name"] = t.Name()
	var fields []interface{}

	for i := 0; i < t.NumField(); i++ {
		sf := t.Field(i)
		// 跳过protobuf生成的内置保留字段
		if sf.Name == "state" || sf.Name == "unknownFields" || sf.Name == "sizeCache" {
			continue
		}

		fieldObj := make(map[string]interface{})
		// 默认取结构体字段名作为输出Name,如需取类型名可在此处修改逻辑
		fieldObj["Name"] = sf.Name
		fieldType := sf.Type

		// 循环解引用所有指针层级
		for fieldType.Kind() == reflect.Ptr {
			fieldType = fieldType.Elem()
		}

		// 嵌套结构体递归处理
		if fieldType.Kind() == reflect.Struct {
			fieldObj["Type"] = "struct"
			subSchema := buildStructSchema(fieldType)
			fieldObj["Fields"] = subSchema["Fields"]
		} else {
			// 基础类型直接赋值类型字符串
			fieldObj["Type"] = fieldType.Kind().String()
		}

		fields = append(fields, fieldObj)
	}

	schema["Fields"] = fields
	return schema
}

// 入口方法,兼容传入结构体指针/结构体值
func GetStructSchema(v interface{}) (map[string]interface{}, error) {
	t := reflect.TypeOf(v)
	// 解引用顶层指针
	for t.Kind() == reflect.Ptr {
		t = t.Elem()
	}
	if t.Kind() != reflect.Struct {
		return nil, fmt.Errorf("input must be struct or struct pointer")
	}
	return buildStructSchema(t), nil
}

func main() {
	schema, err := GetStructSchema(&Data{})
	check(err)
	// 带缩进序列化,和示例输出格式一致
	jsonData, err := json.MarshalIndent(schema, "", "  ")
	check(err)
	fmt.Println(string(jsonData))
}
补充说明
  • 上述代码运行后输出的Types字段Name为字段名Types,和你给出的示例中写的Details不一致,这是因为你定义的结构体中该字段的名称就是Types,如果需要输出类型名而非字段名,把fieldObj["Name"] = sf.Name替换为指针/非指针场景下取类型名的逻辑即可。
  • 现有逻辑已经支持任意深度的结构体嵌套,包括多级指针、多级嵌套结构体的场景。如果后续需要支持切片、map、枚举等类型,只需要在类型判断分支追加对应处理逻辑,递归框架不需要修改。
  • 你给出的目标JSON示例末尾缺少一个闭合大括号,序列化输出时会自动生成标准合法的JSON格式。

内容的提问来源于stack exchange,提问作者sachin srinivasan

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.28 11:57:12