Go语言JSON反序列化:将数组字段保留为JSON字符串的问题
解决Go JSON反序列化时将数组保留为JSON字符串的问题
这个panic的原因很直白:Go的JSON包默认会尝试把JSON数组直接映射到string类型字段,类型不匹配自然会触发错误。要实现把数组原样保留为JSON字符串,我们可以通过自定义JSON反序列化逻辑来解决,下面是具体方案:
方法一:自定义类型实现json.Unmarshaler接口
这是最灵活的方案,我们可以定义一个字符串别名类型,通过实现UnmarshalJSON方法接管反序列化过程:
- 定义自定义类型
// RawJSONString 是string的别名,专门用于存储原始JSON格式的字符串 type RawJSONString string
- 实现
json.Unmarshaler接口
func (r *RawJSONString) UnmarshalJSON(data []byte) error { // 直接把原始的JSON字节数组转成字符串存储,跳过类型转换逻辑 *r = RawJSONString(data) return nil }
- 修改你的
Thing结构体
把原来的B string替换成我们的自定义类型:
type Thing struct { A int `json:"a"` B RawJSONString `json:"b"` // 使用自定义类型接收原始JSON }
- 测试验证
package main import ( "encoding/json" "fmt" ) type RawJSONString string func (r *RawJSONString) UnmarshalJSON(data []byte) error { *r = RawJSONString(data) return nil } type Thing struct { A int `json:"a"` B RawJSONString `json:"b"` } func main() { jsonData := []byte(`{"a": 1, "b": [1,2,3,4]}`) var t Thing if err := json.Unmarshal(jsonData, &t); err != nil { panic(err) } fmt.Printf("A: %d\n", t.A) fmt.Printf("B (JSON字符串): %s\n", t.B) // 输出结果: // A: 1 // B (JSON字符串): [1,2,3,4] // 如果之后需要把B转回数组,也很方便: var bSlice []int if err := json.Unmarshal([]byte(t.B), &bSlice); err != nil { panic(err) } fmt.Printf("B转回数组: %v\n", bSlice) }
方法二:使用json.RawMessage(轻量快捷方案)
如果你不想额外定义类型,也可以直接用Go标准库的json.RawMessage,它本质是[]byte的别名,能直接存储原始JSON数据,之后再转成字符串即可:
import "encoding/json" type Thing struct { A int `json:"a"` B json.RawMessage `json:"b"` } func main() { jsonData := []byte(`{"a": 1, "b": [1,2,3,4]}`) var t Thing if err := json.Unmarshal(jsonData, &t); err != nil { panic(err) } // 转成字符串使用 bStr := string(t.B) fmt.Printf("B: %s\n", bStr) // 输出: [1,2,3,4] }
这种方案的优势是无需额外定义类型,适合快速实现;缺点是B的类型是json.RawMessage(本质是字节数组),如果需要频繁作为字符串使用,每次都要手动转换,不如自定义类型顺手。
两种方案的核心思路都是保留原始JSON字节数据,跳过JSON包默认的类型转换逻辑,完美解决你遇到的类型不匹配问题。
内容的提问来源于stack exchange,提问作者Breedly
相关产品推荐
相关产品推荐

