Go json.Unmarshal后用指针修改map值时出现无法取地址错误问题
报错原因
Go 语言中map 类型的元素值是不可寻址的,这是报错的核心原因。
map 的底层实现是哈希表,运行时会动态扩容、调整元素的存储位置,Go 语言直接禁止了对 map 元素取地址的操作,避免指针指向无效的内存地址。你尝试取 gold 字段的地址时,该字段属于 map 的元素,所以编译器直接抛出错误。
此外你反序列化后 gold 字段的默认类型是 interface{},就算可以取到地址,后续操作也需要额外做类型断言,反而会增加代码复杂度。
解决方法
有两种常用的方案可以简化嵌套字段的操作:
方案1:持有最内层嵌套的 map 引用
map 本身是引用类型,你只需要拿到存储 gold 字段的最内层 map,后续直接操作这个 map 变量就可以同步修改原数据,不需要额外取指针:
inventory := result["player"].(map[string]interface{})["inventory"].(map[string]interface{}) // 后续直接操作 inventory 即可修改原数据 inventory["gold"] = 100 inventory["diamond"] = 20
这种方式代码改动量最小,性能损耗可以忽略,是临时处理非固定结构 JSON 时最常用的方案。
方案2:提前定义结构体做反序列化(推荐)
如果 JSON 结构是固定的,提前定义对应结构体,反序列化时直接解析到结构体实例中,后续可以直接拿到字段指针做操作:
// 定义对应JSON结构的结构体 type PlayerData struct { Player struct { Inventory struct { Gold int `json:"gold"` } `json:"inventory"` } `json:"player"` } // 反序列化逻辑 var result PlayerData json.Unmarshal([]byte(byteValue), &result) // 直接取字段指针操作 gold := &result.Player.Inventory.Gold *gold = 100
这种方式可以完全避免大量重复的类型断言代码,编译期就能检查类型错误,代码可维护性更高,适合业务场景下固定结构的 JSON 处理。
内容的提问来源于stack exchange,提问作者Ertunc Nese
相关产品推荐
相关产品推荐

