JSON 同时实现 MarshalJSON() 的复合结构的编组
JSON Marshaling of composite structs which both implement MarshalJSON()
我最近遇到了以下问题,还没有找到任何解决方案。我在 Go 中有两种结构类型,我们称它们为 Parent 和 Child。 Child 有一个 *Parent 类型的匿名字段。但是,Parent 有一个名为 "ID" 的字段,它具有第三个结构的类型,我们将其称为 "IDType"(在我的实际问题中,这是一个 dialect/sql.NullInt64)。 IDType 有一个 int 字段和一个 bool 字段。
问题如下:Parent 和 Child 都实施 MarshalJSON() 因为对于 Parent 我只希望 JSON 中的 int 字段和对于 Child 一样。但是,似乎两个 MarshalJSONs 都推断出只有 Parent 的值在最终 JSON.
中编码的结果
也许一个简单的例子更容易理解:
package main
import (
"encoding/json"
"fmt"
"os"
)
type IDType struct {
Value int
Valid bool
}
type Parent struct {
ID IDType `json:"id"`
SomeString string `json:"some_string"`
}
type Child struct {
*Parent
Status int `json:"status"`
}
func (parent *Parent) MarshalJSON() ([]byte, error) {
type Alias Parent
fmt.Println("Parent")
return json.Marshal(struct {
*Alias
ID int `json:"id"`
}{
Alias: (*Alias)(parent),
ID: parent.ID.Value,
})
}
func (child *Child) MarshalJSON() ([]byte, error) {
type Alias Child
fmt.Println("Child")
return json.Marshal(struct {
*Alias
Status int `json:"status"`
}{
Alias: (*Alias)(child),
Status: child.Status,
})
}
func main() {
ID := IDType{Value: 1, Valid: true}
parent := Parent{ID: ID, SomeString: "Hello"}
child := Child{Parent: &Parent{ID: ID, SomeString: "Hello"}, Status: 1}
json.NewEncoder(os.Stdout).Encode(&parent)
json.NewEncoder(os.Stdout).Encode(&child)
}
输出为:
Parent
{"some_string":"Hello","id":1}
Child
Parent
{"some_string":"Hello","id":1}
我希望是这样的:
Parent
{"some_string":"Hello","id":1}
Child
Parent
{"some_string":"Hello","id":1, "status": 1}
您应该有一个指向父级的命名指针或父级的嵌入值。
选项 1 会给你 JSON 你所期望的。
type Child struct {
Parent
Status int `json:"status"`
}
>> {"some_string":"Hello","id":1, "status": 1}
选项 2 将父节点作为子节点。
type Child struct {
Parent *Parent
Status int `json:"status"`
}
>> {Parent: {"some_string":"Hello","id":1}, "status": 1}
另一个 hacky 选项是单独编组父子,然后通过剪切 last/first 个字符手动加入,加入 ,
并包裹在 {}
.
由于自定义 ID 封送处理,您似乎只定义了自定义封送处理逻辑。仅为未嵌入的 IDType
类型定义自定义封送处理,因此封送其他类型不会造成任何问题:
func (id *IDType) MarshalJSON() ([]byte, error) {
return json.Marshal(id.Value)
}
并且不需要其他自定义封送处理。这样,输出将是:
{"id":1,"some_string":"Hello"}
{"id":1,"some_string":"Hello","status":1}
在 Go Playground 上试用。
我最近遇到了以下问题,还没有找到任何解决方案。我在 Go 中有两种结构类型,我们称它们为 Parent 和 Child。 Child 有一个 *Parent 类型的匿名字段。但是,Parent 有一个名为 "ID" 的字段,它具有第三个结构的类型,我们将其称为 "IDType"(在我的实际问题中,这是一个 dialect/sql.NullInt64)。 IDType 有一个 int 字段和一个 bool 字段。
问题如下:Parent 和 Child 都实施 MarshalJSON() 因为对于 Parent 我只希望 JSON 中的 int 字段和对于 Child 一样。但是,似乎两个 MarshalJSONs 都推断出只有 Parent 的值在最终 JSON.
中编码的结果也许一个简单的例子更容易理解:
package main
import (
"encoding/json"
"fmt"
"os"
)
type IDType struct {
Value int
Valid bool
}
type Parent struct {
ID IDType `json:"id"`
SomeString string `json:"some_string"`
}
type Child struct {
*Parent
Status int `json:"status"`
}
func (parent *Parent) MarshalJSON() ([]byte, error) {
type Alias Parent
fmt.Println("Parent")
return json.Marshal(struct {
*Alias
ID int `json:"id"`
}{
Alias: (*Alias)(parent),
ID: parent.ID.Value,
})
}
func (child *Child) MarshalJSON() ([]byte, error) {
type Alias Child
fmt.Println("Child")
return json.Marshal(struct {
*Alias
Status int `json:"status"`
}{
Alias: (*Alias)(child),
Status: child.Status,
})
}
func main() {
ID := IDType{Value: 1, Valid: true}
parent := Parent{ID: ID, SomeString: "Hello"}
child := Child{Parent: &Parent{ID: ID, SomeString: "Hello"}, Status: 1}
json.NewEncoder(os.Stdout).Encode(&parent)
json.NewEncoder(os.Stdout).Encode(&child)
}
输出为:
Parent
{"some_string":"Hello","id":1}
Child
Parent
{"some_string":"Hello","id":1}
我希望是这样的:
Parent
{"some_string":"Hello","id":1}
Child
Parent
{"some_string":"Hello","id":1, "status": 1}
您应该有一个指向父级的命名指针或父级的嵌入值。
选项 1 会给你 JSON 你所期望的。
type Child struct {
Parent
Status int `json:"status"`
}
>> {"some_string":"Hello","id":1, "status": 1}
选项 2 将父节点作为子节点。
type Child struct {
Parent *Parent
Status int `json:"status"`
}
>> {Parent: {"some_string":"Hello","id":1}, "status": 1}
另一个 hacky 选项是单独编组父子,然后通过剪切 last/first 个字符手动加入,加入 ,
并包裹在 {}
.
由于自定义 ID 封送处理,您似乎只定义了自定义封送处理逻辑。仅为未嵌入的 IDType
类型定义自定义封送处理,因此封送其他类型不会造成任何问题:
func (id *IDType) MarshalJSON() ([]byte, error) {
return json.Marshal(id.Value)
}
并且不需要其他自定义封送处理。这样,输出将是:
{"id":1,"some_string":"Hello"}
{"id":1,"some_string":"Hello","status":1}
在 Go Playground 上试用。