英文:
Golang - Customer Unmarshaler/Marshaler on pointer with nil/null value
问题
Golang - 在具有空指针/空值的指针上实现自定义的Unmarshaler/Marshaler
我正在尝试在指针类型上实现自定义的UnmarshalJSON
和MarshalJSON
,但是当JSON数据为null/nil
时,这些函数都不会被调用,就像下面的示例中一样:
package main
import (
"encoding/json"
"fmt"
)
type A struct {
B *B `json:"b,omitempty"`
}
type B int
// 仅用于在调用`fmt.Println`时显示值而不是指针地址
func (b *B) String() string {
if b == nil {
return "nil"
}
return fmt.Sprintf("%d", *b)
}
// 当JSON数据包含null而不是数字值时,此函数不会被触发
func (b *B) UnmarshalJSON(data []byte) error {
fmt.Println("UnmarshalJSON on B called")
var value int
if err := json.Unmarshal(data, &value); err != nil {
return err
}
if value == 7 {
*b = B(3)
}
return nil
}
// 当`B`是指针类型且具有`nil`值时,此函数不会被触发
func (b *B) MarshalJSON() ([]byte, error) {
fmt.Println("MarshalJSON on B called")
if b == nil {
return json.Marshal(0)
}
if *b == 3 {
return json.Marshal(7)
}
return json.Marshal(*b)
}
func main() {
var a A
// 这不会调用`UnmarshalJSON`
json.Unmarshal([]byte(`{ "b": null }`), &a)
fmt.Printf("a: %+v\n", a)
// 这不会调用`MarshalJSON`
b, _ := json.Marshal(a)
fmt.Printf("b: %s\n\n", string(b))
// 这将调用`UnmarshalJSON`
json.Unmarshal([]byte(`{ "b": 7 }`), &a)
fmt.Printf("a: %+v\n", a)
// 这将调用`MarshalJSON`
b, _ = json.Marshal(a)
fmt.Printf("b: %s\n\n", string(b))
}
输出:
a: {B:nil}
b: {}
UnmarshalJSON on B called
a: {B:3}
MarshalJSON on B called
b: {"b":7}
我的问题是:
- 为什么在指针类型上,当值为
null/nil
时,UnmarshalJSON/MarshalJSON
不会被调用? - 我们如何在数据为
null/nil
且类型为指针时,每次都调用UnmarshalJSON/MarshalJSON
,而不是在A
类型上实现UnmarshalJSON/MarshalJSON
并从A
级别修改b
属性?
英文:
Golang - Customer Unmarshaler/Marshaler on pointer with nil/null value
I'm trying to implement custom UnmarshalJSON
and MarshalJSON
on pointer type, however none of this function is called when data from json is null/nil
like in example below:
package main
import (
"encoding/json"
"fmt"
)
type A struct {
B *B `json:"b,omitempty"`
}
type B int
// Only for displaying value instead of
// pointer address when calling `fmt.Println`
func (b *B) String() string {
if b == nil {
return "nil"
}
return fmt.Sprintf("%d", *b)
}
// This function is not triggered when json
// data contains null instead of number value
func (b *B) UnmarshalJSON(data []byte) error {
fmt.Println("UnmarshalJSON on B called")
var value int
if err := json.Unmarshal(data, &value); err != nil {
return err
}
if value == 7 {
*b = B(3)
}
return nil
}
// This function is not triggered when `B`
// is pointer type and has `nil` value
func (b *B) MarshalJSON() ([]byte, error) {
fmt.Println("MarshalJSON on B called")
if b == nil {
return json.Marshal(0)
}
if *b == 3 {
return json.Marshal(7)
}
return json.Marshal(*b)
}
func main() {
var a A
// this won't call `UnmarshalJSON`
json.Unmarshal([]byte(`{ "b": null }`), &a)
fmt.Printf("a: %+v\n", a)
// this won't call `MarshalJSON`
b, _ := json.Marshal(a)
fmt.Printf("b: %s\n\n", string(b))
// this would call `UnmarshalJSON`
json.Unmarshal([]byte(`{ "b": 7 }`), &a)
fmt.Printf("a: %+v\n", a)
// this would call `MarshalJSON`
b, _ = json.Marshal(a)
fmt.Printf("b: %s\n\n", string(b))
}
output:
a: {B:nil}
b: {}
UnmarshalJSON on B called
a: {B:3}
MarshalJSON on B called
b: {"b":7}
My questions are:
- why
UnmarshalJSON/MarshalJSON
is not called withnull/nil
value on pointer type - how we can call
UnmarshalJSON/MarshalJSON
everytime when data isnull/nil
and type is a pointer instead of implementingUnmarshalJSON/MarshalJSON
onA
type and modifyb
property from level ofA
答案1
得分: 1
简而言之
目前,在解组/组合一个Go结构体时,只会发出非零字段,因为nil指针
是Go中的零值之一,因此在这种情况下不会调用UnmarshalJSON/MarshalJSON
。
此外,似乎有一些相关的提案
然而,目前还没有解决方案来解决这个问题。
根据代码 解组器
> 解组器将UnmarshalJSON([]byte("null"))
实现为无操作
// 按照约定,为了近似Unmarshal本身的行为,
// 解组器将`UnmarshalJSON([]byte("null"))`实现为无操作。
type Unmarshaler interface {
UnmarshalJSON([]byte) error
}
英文:
For Short
Currently, unmarshaling/marshaling a Go struct will emit only the non-zero fields, since nil pointer
is one zero value in Go, the UnmarshalJSON/MarshalJSON
is not called in this case.
Also, it seems there are some related proposals
- proposal: encoding/json: add omitzero option
- proposal: encoding/json: allow returning nil from MarshalJSON to omit the field
However, there is no solution to resolve it now.
Per code Unmarshalers
> Unmarshalers implement UnmarshalJSON([]byte("null")) as a no-op
// By convention, to approximate the behavior of Unmarshal itself,
// Unmarshalers implement UnmarshalJSON([]byte("null")) as a no-op.
type Unmarshaler interface {
UnmarshalJSON([]byte) error
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论