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

Go语言如何将含未知键的JSON反序列化为指定结构体切片

Go语言JSON反序列化:将未知键的对象转为结构体切片

给定如下JSON字符串:

{
  "MAINKEY": {
    "key1": 1,
    "key2": [1, 2]
  }
}

需要提取MAINKEY中的内容(键名未知),转换为以下结构体切片:

type Result struct {
    Key   string
    Value []int
}

expectedResult := []Result{
    {"key1", []int{1}},
    {"key2", []int{1, 2}},
}

当前代码的问题

你定义的Outer结构体存在错误:MAINKEY对应的是一个包含多个键值对的对象,而非单个Result实例,因此直接反序列化无法得到预期结果。


方案一:自定义UnmarshalJSON方法(避免直接使用map[string]interface{})

通过为自定义类型实现json.Unmarshaler接口,在反序列化过程中直接完成格式转换:

package main

import (
	"encoding/json"
	"fmt"
)

type Result struct {
	Key   string
	Value []int
}

// 用于接收MAINKEY内容的自定义类型
type MainContent []Result

// 实现json.Unmarshaler接口
func (mc *MainContent) UnmarshalJSON(data []byte) error {
	// 用RawMessage暂存原始JSON,避免解析为任意类型
	tempMap := make(map[string]json.RawMessage)
	if err := json.Unmarshal(data, &tempMap); err != nil {
		return err
	}

	// 遍历处理每个键值对
	for key, rawVal := range tempMap {
		var value []int
		// 先尝试解析为数组
		err := json.Unmarshal(rawVal, &value)
		if err != nil {
			// 失败则尝试解析为单个int,转为长度1的数组
			var singleInt int
			if err := json.Unmarshal(rawVal, &singleInt); err != nil {
				return err
			}
			value = []int{singleInt}
		}
		*mc = append(*mc, Result{Key: key, Value: value})
	}
	return nil
}

type Outer struct {
	Main MainContent `json:"MAINKEY"`
}

func main() {
	input := `{"MAINKEY": {"key1": 1, "key2": [1, 2]}}`

	var cont Outer
	if err := json.Unmarshal([]byte(input), &cont); err != nil {
		fmt.Printf("反序列化错误: %v\n", err)
		return
	}
	fmt.Printf("GOT: %+v\n", cont.Main)

	expectedResult := []Result{
		{"key1", []int{1}},
		{"key2", []int{1, 2}},
	}
	fmt.Printf("WANT: %+v\n", expectedResult)
}

核心逻辑:

  • 用map[string]json.RawMessage临时存储MAINKEY的键值对,保留原始JSON字节,避免直接使用map[string]interface{}
  • 对每个值分别尝试解析为数组或单个整数,统一转换为[]int类型
  • 最终拼接成目标[]Result切片

方案二:使用map[string]interface{}(简单直接)

如果可以接受使用map[string]interface{},代码会更简洁直观:

package main

import (
	"encoding/json"
	"fmt"
)

type Result struct {
	Key   string
	Value []int
}

func main() {
	input := `{"MAINKEY": {"key1": 1, "key2": [1, 2]}}`

	// 反序列化为嵌套map
	var temp map[string]map[string]interface{}
	if err := json.Unmarshal([]byte(input), &temp); err != nil {
		fmt.Printf("反序列化错误: %v\n", err)
		return
	}

	mainContent := temp["MAINKEY"]
	var result []Result
	for key, val := range mainContent {
		var value []int
		switch v := val.(type) {
		case float64:
			// JSON数字默认是float64,转为int后包装成数组
			value = []int{int(v)}
		case []interface{}:
			// 遍历数组元素,转为int
			for _, item := range v {
				if num, ok := item.(float64); ok {
					value = append(value, int(num))
				}
			}
		}
		result = append(result, Result{Key: key, Value: value})
	}

	fmt.Printf("GOT: %+v\n", result)

	expectedResult := []Result{
		{"key1", []int{1}},
		{"key2", []int{1, 2}},
	}
	fmt.Printf("WANT: %+v\n", expectedResult)
}

核心逻辑:

  • 将JSON直接反序列化为嵌套map
  • 遍历MAINKEY对应的map,根据值的类型(单个数字/数组)转换为[]int
  • 组装成目标切片

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.13 08:30:47