如何让Go结构体中JSON字符串字段经json.Marshal转为JSON对象
解决Go中JSON字符串字段序列化为JSON对象的问题
你定义了如下Go结构体:
type Info struct { Ids []string `json:"ids"` assignment string `json:"assignment"` }
其中assignment字段存储的是从文件读取的完整JSON字符串,但执行json.Marshal后,该字段被序列化为带引号的字符串而非预期的JSON对象,以下是两种可行的解决方法:
方法一:使用json.RawMessage类型
将assignment字段的类型从string改为json.RawMessage,它可以直接保留原始JSON的格式,序列化时不会被转义成字符串,同时注意结构体字段首字母必须大写(否则json.Marshal无法访问私有字段):
import "encoding/json" type Info struct { Ids []string `json:"ids"` Assignment json.RawMessage `json:"assignment"` }
使用时直接将JSON字符串转为json.RawMessage类型赋值:
// 假设existingJsonString是读取到的合法JSON字符串 r := Info{ Ids: names, Assignment: json.RawMessage(existingJsonString), } body, err := json.Marshal(r) // 务必处理err,不要忽略错误
方法二:自定义json.Marshaler接口实现
如果不想修改字段类型,可以让Info结构体实现json.Marshaler接口,自定义序列化逻辑,手动将字符串解析为JSON对象后再序列化:
import "encoding/json" type Info struct { Ids []string `json:"ids"` Assignment string `json:"assignment"` // 首字母大写保证可访问 } func (i Info) MarshalJSON() ([]byte, error) { // 临时结构体避免递归调用MarshalJSON type tempInfo Info temp := tempInfo(i) // 先序列化临时结构体,得到包含字符串类型assignment的JSON数据 tempData, err := json.Marshal(temp) if err != nil { return nil, err } // 将JSON数据转为map,替换assignment字段 var resultMap map[string]interface{} if err := json.Unmarshal(tempData, &resultMap); err != nil { return nil, err } // 解析assignment的JSON字符串为JSON对象 var assignmentObj interface{} if err := json.Unmarshal([]byte(i.Assignment), &assignmentObj); err != nil { return nil, err } resultMap["assignment"] = assignmentObj // 重新序列化map得到最终结果 return json.Marshal(resultMap) }
使用方式和原来一致:
r := Info{Ids: names, Assignment: existingJsonString} body, err := json.Marshal(r) // 处理序列化错误
注意事项
- 必须保证
existingJsonString是合法的JSON字符串,否则两种方法都会返回错误,不要忽略json.Marshal返回的错误。 - 结构体字段首字母必须大写,
encoding/json包只能访问公开字段,私有字段会在序列化时被忽略。
内容的提问来源于stack exchange,提问作者James Franco
相关产品推荐
相关产品推荐

