Go自定义map类型JSON反序列化后类型断言失败问题
问题现象
执行Go代码时两种类型断言写法表现不一致:
- 写法1:
def := (abc.(MyType))["def"]运行抛出panic,错误信息为interface conversion: interface {} is map[string]interface {}, not main.MyType - 写法2:
def := (abc.(map[string]interface{}))["def"]可正常执行拿到结果
原理解释
- Go类型断言的匹配规则:类型断言要求接口持有的动态类型和目标类型完全一致,不存在“底层结构相同就可以自动匹配”的逻辑。哪怕
MyType的底层类型就是map[string]interface{},二者在Go的类型系统里也是完全独立的两个类型,不能直接跨类型断言。 - JSON反序列化的默认行为:调用
json.Unmarshal反序列化到MyType类型的data变量时,只有最外层结构会被解析为MyType。对于JSON里的嵌套对象,标准库解析时没有携带外层自定义类型的上下文,遇到对象类型会默认输出为原生的map[string]interface{}类型,不会自动转换为自定义的MyType。 - 取值
abc := data["abc"]时,abc的静态类型是interface{},它实际存储的动态类型就是原生map[string]interface{},自然无法断言为MyType,断言原生map类型就可以成功。
可复现代码
func foo() { type MyType map[string]interface{} str := `{ "abc": { "def": { "mln": true } } }` var data MyType if err := json.Unmarshal([]byte(str), &data); err != nil { fmt.Println(err) return } fmt.Println(data) abc := data["abc"] fmt.Println(abc) // 会触发panic:interface conversion: interface {} is map[string]interface {}, not main.MyType // def := (abc.(MyType))["def"] // 可正常执行 def := (abc.(map[string]interface{}))["def"] fmt.Println(def) }
可选解决思路
如果需要嵌套结构也使用MyType,可参考两种常见方案:
- 手动做类型转换:拿到
map[string]interface{}类型的嵌套值后,显式转成MyType,例如abcMap := abc.(map[string]interface{}); abcMyType := MyType(abcMap) - 为
MyType实现自定义UnmarshalJSON方法,在反序列化逻辑里明确指定嵌套对象的解析类型。
内容的提问来源于stack exchange,提问作者nirvana
相关产品推荐
相关产品推荐

