我想执行一些额外的步骤来初始化我的实现中的数据结构UnmarshalJSON
。在该实现中调用json.Unmarshal(b, type)
自然会导致堆栈溢出。在UnmarshalJSON函数内部调用json.Unmarshal而不会导致堆栈溢出
JSON解码器不断尝试查找,如果有自定义的UnmarshalJSON
实现,然后再调用json.Unmarshal
。
是否有另一种方式做到这一点?只需调用底层的默认实现而不造成这种情况?
我想执行一些额外的步骤来初始化我的实现中的数据结构UnmarshalJSON
。在该实现中调用json.Unmarshal(b, type)
自然会导致堆栈溢出。在UnmarshalJSON函数内部调用json.Unmarshal而不会导致堆栈溢出
JSON解码器不断尝试查找,如果有自定义的UnmarshalJSON
实现,然后再调用json.Unmarshal
。
是否有另一种方式做到这一点?只需调用底层的默认实现而不造成这种情况?
一个简单而常见的方式来避免这种/保护它是创建一个新的类型与所type
关键字,并使用类型conversion通过这种类型的值(该值可能是你原来的值,类型转换是可能的,因为新类型具有原始类型作为其基础类型)。
这是可行的,因为type
关键字创建一个新类型,而新类型将有零方法(它不会“继承”底层类型的方法)。
这是否会导致一些运行时间开销?号从Spec: Type declarations:
具体规则引用适用于数字类型之间或向和从一个串型(非恒定)的转换。这些转换可能会更改
x
的表示形式并导致运行时成本。 所有其他转换仅改变类型,但不改变x
的表示。
我们来看一个例子。我们有一个Person
类型的数字Age
,我们要确保Age
不能为负(小于0
)。
type Person struct {
Name string `json:"name"`
Age int `json:"age"`
}
func (p *Person) UnmarshalJSON(data []byte) error {
type person2 Person
if err := json.Unmarshal(data, (*person2)(p)); err != nil {
return err
}
// Post-processing after unmarshaling:
if p.Age < 0 {
p.Age = 0
}
return nil
}
测试它:
var p *Person
fmt.Println(json.Unmarshal([]byte(`{"name":"Bob","age":10}`), &p))
fmt.Println(p)
fmt.Println(json.Unmarshal([]byte(`{"name":"Bob","age":-1}`), &p))
fmt.Println(p)
输出(尝试在Go Playground):
<nil>
&{Bob 10}
<nil>
&{Bob 0}
当然同样的方法适用于自定义编组(MarshalJSON()
)太:
func (p *Person) MarshalJSON() ([]byte, error) {
// Pre-processing before marshaling:
if p.Age < 0 {
p.Age = 0
}
type person2 Person
return json.Marshal((*person2)(p))
}
测试它:
p = &Person{"Bob", 10}
fmt.Println(json.NewEncoder(os.Stdout).Encode(p))
p = &Person{"Bob", -1}
fmt.Println(json.NewEncoder(os.Stdout).Encode(p))
输出(同一Go Playground为例):
{"name":"Bob","age":10}
<nil>
{"name":"Bob","age":0}
<nil>
一个非常类似的问题是,当你定义为fmt
包的自定义文本表示String() string
方法,并且要使用您修改的默认字符串表示。阅读更多关于它的地方:The difference between t and *t
显示你到目前为止。 –