繁体   English   中英

反序列化为map [string] interface {}作为具体的地图类型

[英]Deserialize into map[string]interface{} as a concrete map type

type Foo struct {
    M map[string]interface{} `json:"m"`
}

type Bar struct {
    I int `json:"i"`
}

type Bar2 struct {
    S string `json:"s"`
}


func do() {
    concreteFoo1 := Foo {
        M: make(map[string]Bar),
    }
    json.Unmarshal([]byte(`{"m": {"a": { "i": 1 }}}`), &concreteFoo1)

    concreteFoo2 := Foo {
        M: make(map[string]Bar2),
    }

    json.Unmarshal([]byte(`{"m": {"a": { "s": "hello" }}}`), &concreteFoo2)

}

无法编译为:

不能在字段值中使用make(map [string] Bar)(type map [string] Bar)作为map [string] interface {}类型

不能在字段值中使用make(map [string] Bar2)(类型map [string] Bar2)作为类型map [string] interface {}

我如何才能编译和支持Foo的两个变体?

Foo.m更改为map[string]Bar而不是您拥有的文件,即可对其进行编译。 要使其正常工作,您需要将Foo.m更改为Foo.M并将Bar.iBar.I Go JSON库不会解组或导出未导出的属性。 将大写属性映射到小写JSON元素需要使用标签。 完整的工作示例在这里

更改此行:M map [string] interface {} json:"m"

进入:M接口{} json:"m"

https://play.golang.org/p/qRxo81amA7

如果可能的Bar类型的集合是无限的,则应使用Stud的答案中的解决方案。 解组后,您只需要执行一个类型声明即可获取map ,这比对map[string]interface{}类型的每个值进行类型声明要好得多。

但是,如果该集合仅限于几种类型,则可以创建一个父Bar类型,该父类型嵌入所有可能的Bar变体列表。 万一嵌入类型的字段可能发生冲突,您仍然可以让嵌入类型实现json.Unmarshaler接口,并对在哪里解组的内容进行一些自定义逻辑。

例如这样的事情:

type BarSet struct {
    *Bar
    *Bar2
}

type Bar struct {
    I int `json:"i"`
}

type Bar2 struct {
    S string `json:"s"`
}

https://play.golang.org/p/tJfqtnP-CX

而且,如果您想尽可能严格,则应创建单独的Foo类型,每种类型都有其独特的M map[string]...字段。

您可以制作通用介面

type Foo struct {
    M map[string]Ibar `json:"m"`
}

type Ibar interface{}

并打开包装。

当您需要变量的特定值时,请进行类型断言。

https://play.golang.org/p/fcs-Yp-ck2

我再次查看,认为自定义拆封器可能是一个不错的选择。

func (f *Foo) UnmarshalJSON(b []byte) error {
    var tmp struct {
        M map[string]json.RawMessage `json:"m"`
    }
    var foo = Foo{
        M: make(map[string]interface{}),
    }
    var err error
    //for key, rawValue := range
    err = json.Unmarshal(b, &tmp)
    if err != nil {
        return err
    }
    for key, rawValue := range tmp.M {
        var bar Bar
        if json.Unmarshal(rawValue, &bar) == nil && bar.I != 0 { // custom check
            foo.M[key] = bar
            continue
        }
        var bar2 Bar2
        if json.Unmarshal(rawValue, &bar2) == nil && bar2.S != "" { // custom check
            foo.M[key] = bar2
            continue
        }
    }
    *f = foo
    return nil
}

好处:

  • 一处逻辑

  • 标准通话UnmarshalJSON

  • 可以处理几个子对象

https://play.golang.org/p/ug9rewqjWw

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM