英文:
Inconsistent result with custom MarshalJSON
问题
在使用自定义的MarshalJSON
函数时,我遇到了一些奇怪的行为。
考虑以下设置:
type ISODate struct {
time.Time
}
var nilTime = (time.Time{}).UnixNano()
func (ct *ISODate) MarshalJSON() ([]byte, error) {
if ct.Time.UnixNano() == nilTime {
return []byte("null"), nil
}
return []byte(fmt.Sprintf("\"%s\"", ct.Time.Format("2006-01-02"))), nil
}
然后,我期望的是,当我将一个ISODate
编组为json
时,得到的日期格式为2006-01-02
。然而,这只在某些情况下发生。
当编组像这样包装的ISODate
时:
var d ISODate = ISODate{Time: time.Date(9999, time.December, 31, 23, 59, 59, 999999999, time.UTC)}
m1 := map[int]ISODate{1: d}
m2 := map[int][]ISODate{1: []ISODate{d}}
b, err := json.Marshal(m1)
b, err = json.Marshal(m2)
它给出以下结果:
{"1":"9999-12-31T23:59:59.999999999Z"}
{"1":["9999-12-31"]}
我期望的是两个ISODate
都像第二个例子那样。
我的问题是,我的实现中是否存在错误,还是这种行为是预期的?
英文:
I have encountered some rather strange behaviour when working with custom MarshalJSON
functions in go
.
Consider the following setup:
type ISODate struct {
time.Time
}
var nilTime = (time.Time{}).UnixNano()
func (ct *ISODate) MarshalJSON() ([]byte, error) {
if ct.Time.UnixNano() == nilTime {
return []byte("null"), nil
}
return []byte(fmt.Sprintf("\"%s\"", ct.Time.Format("2006-01-02"))), nil
}
What I would then expect is that when I marshal an ISODate
to json
I get a date of the format 2006-01-02
. This however only happens in some of the cases.
When marshalling ISODate
s wrapped like so:
var d ISODate = ISODate{Time: time.Date(9999, time.December, 31, 23, 59, 59, 999999999, time.UTC)}
m1 := map[int]ISODate{1: d}
m2 := map[int][]ISODate{1: []ISODate{d}}
b, err := json.Marshal(m1)
b, err = json.Marshal(m2)
It gives the following results:
{"1":"9999-12-31T23:59:59.999999999Z"}
{"1":["9999-12-31"]}
What I would expect is for both ISODate
s to look like the second case.
My question is whether there is some error in my implementation or if this behaviour is expected?
答案1
得分: 1
在第一种情况下,你的自定义编组器没有被调用,而是调用了默认的基于反射的json.Marshaler
:
https://play.golang.org/p/fGxTjKbsM5X
要修复这个问题,将你的函数签名更改为非指针接收器:
// func (ct *ISODate) MarshalJSON() ([]byte, error) { /* ... */ }
func (ct ISODate) MarshalJSON() ([]byte, error) { /* ... */ }
https://play.golang.org/p/rgreJol19FO
编辑:
你可以强制编组器使用指针接收器,并且在不需要特殊的nilTime
值的情况下处理nil
情况:
func (ct *ISODate) MarshalJSON() ([]byte, error) {
// 可以在nil值上调用方法
if ct == nil {
return []byte("null"), nil
}
return []byte(fmt.Sprintf("\"%s\"", ct.Time.Format("2006-01-02"))), nil
}
https://play.golang.org/p/dy2XxS9hSYN
英文:
In the first case your custom marshaller is not getting called - but instead the default reflection-based json.Marshaler
:
https://play.golang.org/p/fGxTjKbsM5X
To fix, change your function signature to a non-pointer receiver:
// func (ct *ISODate) MarshalJSON() ([]byte, error) { /* ... */ }
func (ct ISODate) MarshalJSON() ([]byte, error) { /* ... */ }
https://play.golang.org/p/rgreJol19FO
Edit:
you can coerce the marshaler to use a pointer receiver - and also handle the nil
case without the need for a special nilTime
value:
func (ct *ISODate) MarshalJSON() ([]byte, error) {
// a method can be called on a nil value
if ct == nil {
return []byte("null"), nil
}
return []byte(fmt.Sprintf("\"%s\"", ct.Time.Format("2006-01-02"))), nil
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论