简体   繁体   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)

}

fails to compile with: 无法编译为:

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

cannot use make(map[string]Bar2) (type map[string]Bar2) as type map[string]interface {} in field value 不能在字段值中使用make(map [string] Bar2)(类型map [string] Bar2)作为类型map [string] interface {}

How can I get this to compile, and support both variants of Foo? 我如何才能编译和支持Foo的两个变体?

Change Foo.m to be map[string]Bar instead of what you have, that will allow it to compile. Foo.m更改为map[string]Bar而不是您拥有的文件,即可对其进行编译。 To make it work, you need to change Foo.m to Foo.M and Bar.i to Bar.I . 要使其正常工作,您需要将Foo.m更改为Foo.M并将Bar.iBar.I The Go JSON library will not unmarshal to or marshal from unexported properties. Go JSON库不会解组或导出未导出的属性。 Mapping the uppercase properties to lowercase JSON elements requires using tags. 将大写属性映射到小写JSON元素需要使用标签。 Full working example here . 完整的工作示例在这里

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

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

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

If the set of possible Bar types is infinite you should use the solution from Stud's answer . 如果可能的Bar类型的集合是无限的,则应使用Stud的答案中的解决方案。 After unmarshaling you just need to do one type assertion to get the map , which is much better then doing type assertion on each value of a map[string]interface{} type. 解组后,您只需要执行一个类型声明即可获取map ,这比对map[string]interface{}类型的每个值进行类型声明要好得多。

If, however, the set is limited to only a few types you could create a parent Bar type that embeds the list of all the possible Bar variations. 但是,如果该集合仅限于几种类型,则可以创建一个父Bar类型,该父类型嵌入所有可能的Bar变体列表。 In case there's a possibility that the fields of the embedded types would collide you can still have the embedding type implement the json.Unmarshaler interface and do some custom logic on what to unmarshal where. 万一嵌入类型的字段可能发生冲突,您仍然可以让嵌入类型实现json.Unmarshaler接口,并对在哪里解组的内容进行一些自定义逻辑。

Eg something like this: 例如这样的事情:

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 https://play.golang.org/p/tJfqtnP-CX

And if you want to be as strict as possible you should create separate Foo types, each with their distincitve M map[string]... field. 而且,如果您想尽可能严格,则应创建单独的Foo类型,每种类型都有其独特的M map[string]...字段。

You can make generalized interface 您可以制作通用介面

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

type Ibar interface{}

And unpack into it. 并打开包装。

When you need specific value of variable make type assertion. 当您需要变量的特定值时,请进行类型断言。

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

I've looked again and think custom unmarshaler can be good option. 我再次查看,认为自定义拆封器可能是一个不错的选择。

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
}

Advantages: 好处:

  • Logics in one place 一处逻辑

  • Standard call UnmarshalJSON 标准通话UnmarshalJSON

  • Can handle several subobjects 可以处理几个子对象

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

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

相关问题 在map [string] interface {}的值上键入switch到[] map [string] interface {} - Type switch to []map[string]interface{} on the value of map[string]interface{} 在 Golang 中访问类型 map[string]interface{} 的嵌套映射 - Accessing Nested Map of Type map[string]interface{} in Golang 反序列化为Map <String, String> 与杰克逊 - Deserialize into Map<String, String> with Jackson 杰克逊:反序列化为Map <String,Object>,每个值都有正确的类型 - Jackson: Deserialize to a Map<String, Object> with correct type for each value Scala Jackson反序列化为字符串或映射 - Scala Jackson Deserialize to String or Map json:无法将字符串解组为 map[string]interface {} 类型的 Go 值 - json: cannot unmarshal string into Go value of type map[string]interface {} Jackson fastxml映射器-接口/抽象对象类型列表的序列化/反序列化映射 - Jackson fasterxml mapper - serialize/deserialize map of list of interface/abstract object type 接口转换:接口是map[string]interface {}不是 - interface conversion: interface is map[string]interface {} not 将 map[string]interface{} 类型的 terraform resourceData 转换为 struct - Convert terraform resourceData of type map[string]interface{} to struct 如何将map [string] interface {}转换为其他类型的结构? - How can I turn map[string]interface{} to different type of struct?
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM