英文:
Implementing json marshaller over embedded stuct in Go
问题
我有一个结构体,我想要高效地将其转换为 JSON:
type MyStruct struct {
*Meta
Contents []interface{}
}
type Meta struct {
Id int
}
这个结构体包含了已知形式的元数据和未知形式的 Contents。Contents 列表在运行时被填充,所以我对它们没有完全的控制。为了提高 Go 的编组速度,我想要在 Meta 结构体上实现 Marshaller 接口。Marshaller 接口的定义如下:
type Marshaler interface {
MarshalJSON() ([]byte, error)
}
请注意,Meta 结构体并不像这里展示的那么简单。我尝试在 Meta 结构体上实现 Marshaler 接口,但是当我对 MyStruct 进行 JSON 编组时,结果只包含了 Meta 编组接口返回的结果。
所以我的问题是:我如何对一个包含了具有自己的 JSON 编组器的嵌入结构体和另一个没有编组器的结构体的结构体进行 JSON 编组?
英文:
I have a struct that I would like to efficiently JSON encode:
type MyStruct struct {
*Meta
Contents []interface{}
}
type Meta struct {
Id int
}
The struct contains meta data of a known form and Contents of an unknown form, The contents list is populated during runtime, so I don't really have control over them. To improve Go's marshalling speed, I would like to implement the Marshaller interface over the Meta struct. The Marshaller interface looks like this:
type Marshaler interface {
MarshalJSON() ([]byte, error)
}
Please keep in mind that the Meta struct is not as simple as shown here. I've tried implementing the Marshaler interface over the Meta struct, but it seems that when I then JSON marshal MyStruct, the result is only the result returned by the Meta marshalling interface.
So my question is: How can I JSON marshal a struct, that contains en embedded struct with its own JSON marshaller and another struct without one?
答案1
得分: 4
由于匿名字段*Meta
的MarshalJSON
方法将被提升到MyStruct
中,当MyStruct
被编组时,encoding/json
包将使用该方法。
你可以这样做,而不是让Meta
实现Marshaller
接口,你可以在MyStruct
上实现该接口,代码如下:
package main
import (
"fmt"
"encoding/json"
"strconv"
)
type MyStruct struct {
*Meta
Contents []interface{}
}
type Meta struct {
Id int
}
func (m *MyStruct) MarshalJSON() ([]byte, error) {
// 在这里对 Meta 进行编组
meta := `"Id":` + strconv.Itoa(m.Meta.Id)
// 手动调用 Contents 的编组
cont, err := json.Marshal(m.Contents)
if err != nil {
return nil, err
}
// 将它们拼接在一起
return []byte(`{` + meta + `,"Contents":` + string(cont) + `}`), nil
}
func main() {
str := &MyStruct{&Meta{Id:42}, []interface{}{"MyForm", 12}}
o, err := json.Marshal(str)
if err != nil {
panic(err)
}
fmt.Println(string(o))
}
输出结果为:{"Id":42,"Contents":["MyForm",12]}
英文:
Since the MarshalJSON
method of the anonymous field *Meta
will be promoted to MyStruct
, the encoding/json
package will use that method when MyStruct will be marshalled.
What you can do is, instead of letting Meta
implement the Marshaller
interface, you can implement the interface on MyStruct like this:
package main
import (
"fmt"
"encoding/json"
"strconv"
)
type MyStruct struct {
*Meta
Contents []interface{}
}
type Meta struct {
Id int
}
func (m *MyStruct) MarshalJSON() ([]byte, error) {
// Here you do the marshalling of Meta
meta := `"Id":` + strconv.Itoa(m.Meta.Id)
// Manually calling Marshal for Contents
cont, err := json.Marshal(m.Contents)
if err != nil {
return nil, err
}
// Stitching it all together
return []byte(`{` + meta + `,"Contents":` + string(cont) + `}`), nil
}
func main() {
str := &MyStruct{&Meta{Id:42}, []interface{}{"MyForm", 12}}
o, err := json.Marshal(str)
if err != nil {
panic(err)
}
fmt.Println(string(o))
}
>{"Id":42,"Contents":["MyForm",12]}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论