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
相关产品推荐
相关产品推荐

