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

这是我的问题的人为示例,因此请忽略这是通过使用带有 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

    }


白衣非少年
浏览 145回答 2
2回答

偶然的你

另一个答案的替代方法是声明一个命名map[string]AddressIf类型并让它实现json.Unmarshaler接口,然后你不必做任何临时/匿名类型和转换舞蹈。type AddressMap map[string]AddressIffunc (m *AddressMap) UnmarshalJSON(b []byte) error {&nbsp; &nbsp; if *m == nil {&nbsp; &nbsp; &nbsp; &nbsp; *m = make(AddressMap)&nbsp; &nbsp; }&nbsp; &nbsp; raw := make(map[string]json.RawMessage)&nbsp; &nbsp; if err := json.Unmarshal(b, &raw); err != nil {&nbsp; &nbsp; &nbsp; &nbsp; return err&nbsp; &nbsp; }&nbsp; &nbsp; for key, val := range raw {&nbsp; &nbsp; &nbsp; &nbsp; switch key {&nbsp; &nbsp; &nbsp; &nbsp; case "home":&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; dst := new(AddressHome)&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; if err := json.Unmarshal(val, dst); err != nil {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; return err&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; (*m)[key] = dst&nbsp; &nbsp; &nbsp; &nbsp; case "work":&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; dst := new(AddressWork)&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; if err := json.Unmarshal(val, dst); err != nil {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; return err&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; (*m)[key] = dst&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; }&nbsp; &nbsp; return nil}https://play.golang.org/p/o7zV8zu9g5X

收到一只叮咚

为避免复制联系人字段,请使用对象嵌入来隐藏需要特殊处理的字段。使用工厂模式来消除跨地址类型的代码重复。有关更多信息,请参阅评论:var addressFactories = map[string]func() AddressIf{&nbsp; &nbsp; "home": func() AddressIf { return &AddressHome{} },&nbsp; &nbsp; "work": func() AddressIf { return &AddressWork{} },}func (self *Contact) UnmarshalJSON(b []byte) error {&nbsp; &nbsp; // Declare type with same base type as Contact. This&nbsp; &nbsp; // avoids recursion below because this type does not&nbsp; &nbsp; // have Contact's UnmarshalJSON method.&nbsp; &nbsp; type contactNoMethods Contact&nbsp; &nbsp; // Unmarshal to this value. The Contact.AddressMap&nbsp; &nbsp; // field is shadowed so we can handle unmarshal of&nbsp; &nbsp; // each value in the map.&nbsp; &nbsp; var data = struct {&nbsp; &nbsp; &nbsp; &nbsp; *contactNoMethods&nbsp; &nbsp; &nbsp; &nbsp; AddressMap map[string]json.RawMessage `json:"address_map"`&nbsp; &nbsp; }{&nbsp; &nbsp; &nbsp; &nbsp; // Note that all fields except AddressMap are unmarshaled&nbsp; &nbsp; &nbsp; &nbsp; // directly to Contact.&nbsp; &nbsp; &nbsp; &nbsp; (*contactNoMethods)(self),&nbsp; &nbsp; &nbsp; &nbsp; nil,&nbsp; &nbsp; }&nbsp; &nbsp; if err := json.Unmarshal(b, &data); err != nil {&nbsp; &nbsp; &nbsp; &nbsp; return err&nbsp; &nbsp; }&nbsp; &nbsp; // Unmarshal each addresss...&nbsp; &nbsp; self.AddressMap = make(map[string]AddressIf, len(data.AddressMap))&nbsp; &nbsp; for k, raw := range data.AddressMap {&nbsp; &nbsp; &nbsp; &nbsp; factory := addressFactories[k]&nbsp; &nbsp; &nbsp; &nbsp; if factory == nil {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; return fmt.Errorf("unknown key %s", k)&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; address := factory()&nbsp; &nbsp; &nbsp; &nbsp; if err := json.Unmarshal(raw, address); err != nil {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; return err&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; self.AddressMap[k] = address&nbsp; &nbsp; }&nbsp; &nbsp; return nil}&nbsp;在对该问题的评论中,OP 表示不应使用其他类型。这个答案使用了两种额外contactNoMethods的类型(和匿名类型data)。
打开App,查看更多内容
随时随地看视频慕课网APP

相关分类

Go