为了账号安全,请及时绑定邮箱和手机立即绑定

结构中的golang解组(反序列化)变量类型字典

结构中的golang解组(反序列化)变量类型字典

Go
白衣非少年 2022-06-21 10:00:49
这是我的问题的人为示例,因此请忽略这是通过使用带有 json 可选参数的奇异结构来解决的。鉴于:    {        "name": "alice",        "address_dict": {                            "home": { "address": "123 st" },                            "work": { "address": "456 rd", "suite": "123"}                        }    }type AddressIf interface{}type AddressHome {    Address string `json:"address"`}type AddressWork {    Address string `json:"address"`    Suite string `json:"suite"`}type Contact struct {    Name string `json:"name"`    AddressMap map[string]AddressIf `json:"address_map"`}func(self *Contact) UnmarshalJSON(b []byte) error {    var objMap map[string]*json.RawMessage    err := json.Unmarshal(b, &objMap    if err != nil {        return err    }    var rawAddressMap map[string]*json.RawMessage    err = json.Unmarshal(*objMap["address_map"], &rawAddressMap)    if err != nil {        return err    }    // how do we unmarshal everything else in the struct, and only override the handling of address map???    // <failing code block is here - beg - just a tad, just a tad, just a tad - recursive>    err = json.Unmarshal(b, self)    if err != nil {        return err    }    // <failing code block is here - end>    if nil == self.AddressMap {        self.AddressMap = make(map[string]AddressIf)    }    for key, value := range rawAddressMap {        switch key {            case "home":                dst := &AddressHome{}                err := json.Unmarshal(*value, dst)                if err != nil {                    return err                } else {                    self.AddressMap[key] = dst                }        }    }}我只有name这个 json 示例位中的参数,但假设我的代码中有更多参数。address_dict有没有办法对所有参数使用普通/默认解组,然后只手动接管?我尝试了以下方法,并很快意识到为什么它不起作用。    err = json.Unmarshal(b, self)    if err != nil {        return err    }
查看完整描述

2 回答

?
偶然的你

TA贡献1841条经验 获得超3个赞

另一个答案的替代方法是声明一个命名map[string]AddressIf类型并让它实现json.Unmarshaler接口,然后你不必做任何临时/匿名类型和转换舞蹈。


type AddressMap map[string]AddressIf


func (m *AddressMap) UnmarshalJSON(b []byte) error {

    if *m == nil {

        *m = make(AddressMap)

    }


    raw := make(map[string]json.RawMessage)

    if err := json.Unmarshal(b, &raw); err != nil {

        return err

    }


    for key, val := range raw {

        switch key {

        case "home":

            dst := new(AddressHome)

            if err := json.Unmarshal(val, dst); err != nil {

                return err

            }

            (*m)[key] = dst

        case "work":

            dst := new(AddressWork)

            if err := json.Unmarshal(val, dst); err != nil {

                return err

            }

            (*m)[key] = dst

        }

    }

    return nil

}

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


查看完整回答
反对 回复 2022-06-21
?
收到一只叮咚

TA贡献1821条经验 获得超5个赞

为避免复制联系人字段,请使用对象嵌入来隐藏需要特殊处理的字段。


使用工厂模式来消除跨地址类型的代码重复。


有关更多信息,请参阅评论:


var addressFactories = map[string]func() AddressIf{

    "home": func() AddressIf { return &AddressHome{} },

    "work": func() AddressIf { return &AddressWork{} },

}


func (self *Contact) UnmarshalJSON(b []byte) error {


    // Declare type with same base type as Contact. This

    // avoids recursion below because this type does not

    // have Contact's UnmarshalJSON method.

    type contactNoMethods Contact


    // Unmarshal to this value. The Contact.AddressMap

    // field is shadowed so we can handle unmarshal of

    // each value in the map.

    var data = struct {

        *contactNoMethods

        AddressMap map[string]json.RawMessage `json:"address_map"`

    }{

        // Note that all fields except AddressMap are unmarshaled

        // directly to Contact.

        (*contactNoMethods)(self),

        nil,

    }


    if err := json.Unmarshal(b, &data); err != nil {

        return err

    }


    // Unmarshal each addresss...


    self.AddressMap = make(map[string]AddressIf, len(data.AddressMap))

    for k, raw := range data.AddressMap {

        factory := addressFactories[k]

        if factory == nil {

            return fmt.Errorf("unknown key %s", k)

        }

        address := factory()

        if err := json.Unmarshal(raw, address); err != nil {

            return err

        }

        self.AddressMap[k] = address

    }

    return nil

}

 

在对该问题的评论中,OP 表示不应使用其他类型。这个答案使用了两种额外contactNoMethods的类型(和匿名类型data)。


查看完整回答
反对 回复 2022-06-21
  • 2 回答
  • 0 关注
  • 144 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
微信客服

购课补贴
联系客服咨询优惠详情

帮助反馈 APP下载

慕课网APP
您的移动学习伙伴

公众号

扫描二维码
关注慕课网微信公众号