type FieldDefinition struct {
Name string `json:"name"`
Description string `json:"description"`
Aspects map[string]string `json:"aspects"`
}
func (f *FieldDefinition) UnmarshalJSON(b []byte) error {
var tmp struct {
Name string `json:"name"`
Description string `json:"description"`
Aspects map[string]string `json:"aspects"`
}
err := json.Unmarshal(b, &tmp)
if err != nil {
return err
}
if tmp.Aspects == nil {
tmp.Aspects = make(Aspects)
}
*f = tmp
return nil
}
如果我在没有aspects
字段的情况下解组{"description": "desc","name": "name"}
,则Aspects
将为空。
可以通过添加UnmarshalJSON
函数来解决。
但是有两个问题,一个是如果一个strcut嵌入了FieldDefinition
,比如
type PropertyDefinition struct {
FieldDefinition
SourceName string `json:"sourceName"`
}
json.Unmarshal
将调用FieldDefinition.UnmarshalJSON
,而不修改SourceName
。
我也可以添加PropertyDefinition.UnmarshalJson
,但它具有传染性。
另一个是tmp
结构体重复了FieldDefinition
,这是次要的,我可以忍受。
https://github.com/golang/go/issues/27589相关。
1条答案
按热度按时间yiytaume1#
tmp结构重复了FieldDefinition,这是次要的,我可以忍受。
您不需要这样做。您可以在
FieldDefinition
上创建另一个类型,新类型将不具有UnmarshalJSON
方法,例如:关于
FieldDefinition.UnmarshalJSON
暴露在嵌入它的结构体中的另一个问题,不幸的是,如果从标准库中使用encoding/json
是一个要求,那么没有一个好的方法来解决这个问题。如果将它作为一个命名字段,而不是嵌入一个选项,那么这将不再是一个问题。但是我不认为您需要定制的
UnmarshalJSON
来确保map在开始时总是非空的。如果
Aspects
Map对它的使用者来说是只读的,那么go对nilMap的处理应该已经很好地适用于这个用例了,因为从nilMap中阅读一个键并不会出现异常--它只会表现得好像这个键不存在一样:此外,如果使用者需要消除是否设置了
Aspects
Map的歧义,他们现在可以检查该struct字段是否为nil
。所以这是假设
Aspects
Map是只读的。如果消费者在JSON解码后还要更新
Aspects
Map,那么您可以1)期望消费者负责检查nil并在需要时示例化Map,或者2)提供一个helper方法,例如FieldDefinition.SetAspectField(string, string)
,它可以为消费者处理Map的示例化。编辑:提到如果
Aspect
Map已经非空,则在FieldDefinition.UnmarshalJSON
中处理Map合并