Go反序列化含动态键的JSON时嵌套结构体值解析异常问题
问题原因
你的代码存在编写错误,最终导致动态字段解析失败:
- 结构体JSON标签和实际JSON结构不匹配:你给出的JSON数据里,
bvu62fu6dq这类动态键是和name、age平级的顶层字段,不存在顶层的status键。但你给Person结构体的Status字段设置了json:"status"标签,等于告诉解析器仅将顶层键名为status的内容映射到该字段,所有动态键的内容都会被忽略,最终Status是个空map。 - 空map读取不存在的key会返回对应类型的零值:你从空map里取
bvu62fu6dq对应的值,拿到的是Status结构体的零值,其Status字段默认就是false,和嵌套结构解析逻辑无关。
补充:你的Status结构体的Status字段没有显式添加json:"status"标签,虽然Go标准库json解析默认做大小写不敏感匹配能识别,但显式配置标签可以避免不同解析库、特殊配置下的匹配异常。
修复方案
最稳妥的修复方式是通过自定义UnmarshalJSON方法,分别处理固定字段和动态字段;高版本Go也可以通过json:",inline"标签简化实现,以下是兼容性最好的可运行代码:
package main import ( "encoding/json" "fmt" "io" "log" "strings" ) const jsonStream = `{ "name": "john", "age": 23, "bvu62fu6dq": { "status": true } }` type Status struct { Status bool `json:"status"` // 显式配置标签匹配小写键名 } type Person struct { Name string `json:"name"` Age int `json:"age"` Status map[string]Status // 移除固定的status标签,用于承接所有动态键 } // 自定义反序列化逻辑 func (p *Person) UnmarshalJSON(data []byte) error { // 先把所有顶层键解析为原始JSON消息 rawFields := make(map[string]json.RawMessage) if err := json.Unmarshal(data, &rawFields); err != nil { return err } // 初始化动态字段存储的map p.Status = make(map[string]Status) for key, rawVal := range rawFields { switch key { case "name": if err := json.Unmarshal(rawVal, &p.Name); err != nil { return err } case "age": if err := json.Unmarshal(rawVal, &p.Age); err != nil { return err } default: // 其余所有动态键,统一解析为Status结构体存入map var s Status if err := json.Unmarshal(rawVal, &s); err != nil { return err } p.Status[key] = s } } return nil } func main() { dec := json.NewDecoder(strings.NewReader(jsonStream)) for { var person Person if err := dec.Decode(&person); err == io.EOF { break } else if err != nil { log.Fatal(err) } fmt.Println(person) fmt.Println(person.Status["bvu62fu6dq"]) } }
运行结果
修复后代码执行输出如下,符合预期:
{john 23 map[bvu62fu6dq:{true}]} {true}
内容的提问来源于stack exchange,提问作者Akshay
相关产品推荐
相关产品推荐

