[英]Custom JSON serialization and deserialization for interfaces in Go
我目前正在为golang中的博客开发JSON API,并且遇到了处理博客文章的序列化和反序列化的障碍。 我希望我的帖子包含一系列帖子部分,这些部分可以是很多东西(例如普通段落,图像,引号等)。 我正在使用Mongo进行存储(带有令人惊叹的mgo库 ),我想保存这样的帖子:
{
"title": "Blog post",
"sections": [
{
"type": "text",
"content": { "en": "English content", "de": "Deutscher Inhalt" }
},
{
"type": "image",
"content": "https://dummyimage.com/100x100"
},
...more sections
],
...other fields
}
我已经尝试了几种解决方案来实现此目标,但似乎没有一种真正的“正确方法”:
这似乎是显而易见的解决方案,仅使用简单的结构即可:
type PostSection struct{
Type string
Content interface{}
}
这样,我可以遍历任何前端POSTS并保存它。 但是,操作或验证数据变得不可能,因此这不是一个好的解决方案。
我发现这篇关于在golang中序列化接口的文章。 一开始这看起来很棒,因为我可以有一个像这样的界面:
type PostSection interface{
Type() string
Content() interface{}
}
然后实现这样的每种类型:
type PostImage string
func (p *PostImage) Type() string {
return "image"
}
func (p *PostImage) Content() interface{} {
return p
}
理想的情况就是这样,在为我所有的类型实现MarshalJSON
和UnmarshalJSON
之后,直接在PostSection对象上使用json.Marshal时,它运行良好。
但是,当对包含PostSection
数组的整个Post对象进行序列化或反序列化时,我的自定义代码将被忽略,并且在序列化时,PostSections将仅被视为基础对象(示例中为string
或map[string]string
),或反序列化时导致空对象。
因此,我当前正在使用但想更改的解决方案是针对整个Post对象的自定义序列化。 这导致代码非常丑陋,因为我只需要单个字段的自定义代码,因此我将遍历其余部分,从而使反序列化看起来类似于以下内容:
p.ID = decoded.ID
p.Author = decoded.Author
p.Title = decoded.Title
p.Intro = decoded.Intro
p.Slug = decoded.Slug
p.TitleImage = decoded.TitleImage
p.Images = decoded.Images
...more fields...
然后,像这样解码这些部分:
sections := make([]PostSection, len(decoded.Sections))
for i, s := range decoded.Sections {
if s["type"] == "text" {
content := s["content"].(map[string]interface{})
langs := make(PostText, len(content))
for lang, langContent := range content {
langString := langContent.(string)
langs[lang] = langString
}
sections[i] = &langs
} else if s["type"] == "image" {
content := s["content"].(string)
contentString := PostImage(content)
sections[i] = &contentString
}
}
p.Sections = sections
每当我想在其他地方(例如在新闻通讯中)以另一种形式包含PostSections时,都必须使用大量的代码,而且从长远来看,它并不像惯用的go代码。 另外,对于格式错误的部分也没有错误处理-它们只会引起类似的恐慌。
有没有解决这个问题的解决方案?
为了避免为整个Post
编写UnmarshalJSON
,可以将PostSection
包装为具体类型,并使其实现Unmarshaler接口。
type Post struct {
ID int
Author string
Title string
Intro string
Slug string
TitleImage string
Images []string
Sections []*PostSection
}
type SectionContent interface {
Type() string
Content() interface{}
}
type PostSection struct {
Content SectionContent
}
func (s *PostSection) UnmarshalJSON(data []byte) error {
// ...
return nil
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.