我想UnmarshalJSON是一个包含接口的结构,如下所示:
type Filterer interface {
Filter(s string) error
}
type FieldFilter struct {
Key string
Val string
}
func (ff *FieldFilter) Filter(s string) error {
// Do something
}
type Test struct {
Name string
Filters []Filterer
}
我的想法是像这样发送一个json:
{
"Name": "testing",
"Filters": [
{
"FieldFilter": {
"Key": "key",
"Val": "val"
}
}
]
}
但是,当将此json发送到unmarshaler时,会返回以下异常:json: cannot unmarshal object into Go struct field Test.Filters of type Filterer
我完全理解这个问题,但不知道如何明智地解决这个问题。在go中寻找解决这个问题的惯用方法的建议。
答案 0 :(得分:2)
Unmarshal无法知道它应该使用什么类型。唯一可以“制造东西”的情况是,如果要求它解组为interface{}
,在这种情况下它将使用the rules in the documentation。由于这些类型都不能放入[]Filterer
,因此无法解组该字段。如果要解组为struct
类型,则必须将该字段指定为该类型。
您可以随时解组为中间结构或地图类型,然后将其自己转换为您想要的任何类型。
答案 1 :(得分:2)
根据我自己的问题,我研究了如何为接口列表实现UnmarshalJSON。最终,这导致我发布了一篇关于如何正确执行此操作的博客文章。基本上有两个主要的解决方案:
map[string]*json.RawMessage
并从那里开始工作。map[string]*json.RawMessage
和一些手动工作。什么都没有价格!我强烈建议采用秒针方法。虽然这两种解决方案可能会产生相同数量的代码行,但利用类型别名并减少对json.RawMessage
类型的依赖将使代码更易于管理,尤其是当需要支持多个接口时UnmarshalJSON实现
要直接回答问题,请先为接口列表创建类型别名:
type Filterers []Filterer
现在继续实现JSON的解码:
func (f *Filterers) UnmarshalJSON(b []byte) error {
var FilterFields map[string]*json.RawMessage
if err := json.Unmarshal(b, &FilterFields); err != nil {
return err
}
for LFKey, LFValue := range FilterFields {
if LFKey == "FieldFilter" {
var MyFieldFilters []*json.RawMessage
if err := json.Unmarshal(*LFValue, &MyFieldFilters); err != nil {
return err
}
for _, MyFieldFilter := range MyFieldFilters {
var filter FieldFilter
if err := json.Unmarshal(*MyFieldFilter, &filter); err != nil {
return err
}
*f = append(*f, &filter)
}
}
}
return nil
}
第二种方法的详细解释(包含一些示例和完整的工作代码片段)on my own blog