【问题标题】:Unmarshalling array into struct将数组解组为结构
【发布时间】:2018-07-25 10:07:22
【问题描述】:

我试图弄清楚如何(使用 gin)从 api 调用创建结构

"icon": [
        "https://api.figo.me/assets/images/accounts/postbank.png",
        {
          "48x48": "https://api.figo.me/assets/images/accounts/postbank_48.png",
          "60x60": "https://api.figo.me/assets/images/accounts/postbank_60.png",
          "72x72": "https://api.figo.me/assets/images/accounts/postbank_72.png",
          "84x84": "https://api.figo.me/assets/images/accounts/postbank_84.png",
          "96x96": "https://api.figo.me/assets/images/accounts/postbank_96.png",
          "120x120": "https://api.figo.me/assets/images/accounts/postbank_120.png",
          "144x144": "https://api.figo.me/assets/images/accounts/postbank_144.png",
          "192x192": "https://api.figo.me/assets/images/accounts/postbank_192.png",
          "256x256": "https://api.figo.me/assets/images/accounts/postbank_256.png"
        }
      ],

进入

type CatalogBank struct {
        Advice      string `json:"advice"`
        BankCode    string `json:"bank_code"`
        BankName    string `json:"bank_name"`
        BIC         string `json:"bic"`
        Credentials []struct {
            Label  string `json:"label"`
            Masked bool   `json:"masked"`
        } `json:"credentials"`
        Icon     []struct {

        } `json:"icon"`
        Language []byte `json:"language"`
    }

图标部分只是一个摘录,但我总是收到这部分的解组错误。我将如何定义结构中的“图标”部分?

【问题讨论】:

标签: go struct type-conversion


【解决方案1】:

这样就可以了

package main

type CatalogBank struct {
   Icon []interface{} `json:"icon"`
}

【讨论】:

    【解决方案2】:

    由于 JSON 中的非严格类型,这在 Golang 中有点棘手。如果这绝对是您要接收数据的格式,您应该解组为 Interface{},然后将接口解析为可以在 Golang 中使用的结构

    无法直接解组,因为每个字段的类型未知

    type Icon struct{
        ImageLink string
        ImageLink48 string
        // ...
    }
    
    type CatalogBank struct {
        Advice      string `json:"advice"`
        IconRaw     []interface{} `json:"icon"`
        Icon        []Icon
        //...
    }
    
    func UnmarshalIcon(c &CatalogBank, i interface{}):
        // first convert it to the top level list
        newIcon := Icon{}
        listOfIcons := i.([]interface{})
        for _, i := range listOfIcons:
            switch iT := i.(type) {
               case string:
                    newIcon.ImageLink = iT
               case map[string]interface{}:
                  for smallIconsKey, smallIconLink := range iT {
                      if smallIconsKey == "48x48"{
                             newIcon.ImageLink48 = smallIconLink.(string)
                      }
                      // and so on
            }
    
    
    var c CatalogBank{}
    _ := json.Unmarshal([]byte(your_json), &c)
    for _, i := range c.IconRaw:
       UnmarshalIcon(&c, i)
    

    Caveat Emptor:我没有检查上面的实现,但它应该是这样的

    【讨论】:

      【解决方案3】:

      您不能将 []struct {} 用于图标,而是将其更改为 []interface{},或者如果您想对类型安全类型进行操作,请查看使用 cusom unmarshaler 的第二个解决方案

      解决方案 1

          package main
      
          import (
              "encoding/json"
              "fmt"
              "log"
          )
      
          type CatalogBank struct {
              Advice   string `json:"advice"`
              BankCode string `json:"bank_code"`
              BankName string `json:"bank_name"`
              BIC      string `json:"bic"`
              Credentials []struct {
                  Label  string `json:"label"`
                  Masked bool   `json:"masked"`
              } `json:"credentials"`
              Icon []interface{} `json:"icon"`
              Language []byte `json:"language"`
          }
      
          func main() {
      
              data := `
          {
          "Advice":"abc",
          "icon": [
                  "https://api.figo.me/assets/images/accounts/postbank.png",
                  {
                    "48x48": "https://api.figo.me/assets/images/accounts/postbank_48.png",
                    "60x60": "https://api.figo.me/assets/images/accounts/postbank_60.png",
                    "72x72": "https://api.figo.me/assets/images/accounts/postbank_72.png",
                    "84x84": "https://api.figo.me/assets/images/accounts/postbank_84.png",
                    "96x96": "https://api.figo.me/assets/images/accounts/postbank_96.png",
                    "120x120": "https://api.figo.me/assets/images/accounts/postbank_120.png",
                    "144x144": "https://api.figo.me/assets/images/accounts/postbank_144.png",
                    "192x192": "https://api.figo.me/assets/images/accounts/postbank_192.png",
                    "256x256": "https://api.figo.me/assets/images/accounts/postbank_256.png"
                  }
                ]
          }
          `
      
              bank := &CatalogBank{}
      
              err := json.Unmarshal([]byte(data), bank)
              if err != nil {
                  log.Fatal(err)
              }
              for _, icon := range bank.Icon {
                  fmt.Printf(" %v\n ", icon)
              }
      
          }
      

      解决方案 2:

          package main
      
          import (
              "encoding/json"
              "fmt"
              "log"
          )
      
          type Icons struct {
              URL    string
              BySize map[string]string
          }
      
      
      
          type CatalogBank struct {
              Advice   string `json:"advice"`
              BankCode string `json:"bank_code"`
              BankName string `json:"bank_name"`
              BIC      string `json:"bic"`
              Credentials []struct {
                  Label  string `json:"label"`
                  Masked bool   `json:"masked"`
              } `json:"credentials"`
              Icon     *Icons `json:"-,"`
              Language []byte `json:"language"`
          }
      
          func (p *CatalogBank) Unmarshal(data []byte) error {
      
      
              type Transient struct {
                  *CatalogBank
                  Icon []interface{} `json:"icon"`
              }
      
              var transient = &Transient{CatalogBank:p}
              err := json.Unmarshal([]byte(data), transient)
              if err != nil {
                  return err
              }
              p.Icon = &Icons{
                  BySize: make(map[string]string),
              }
      
              if len(transient.Icon) > 0 {
                  if url, ok := transient.Icon[0].(string); ok {
                      p.Icon.URL = url
                  }
                  if aMap, ok := transient.Icon[1].(map[string]interface{}); ok {
                      for k, v := range aMap {
                          p.Icon.BySize[k] = v.(string)
                      }
                  }
              }
              return nil
          }
      
          func main() {
      
              data := `
                  {
                  "Advice":"abc",
                  "icon": [
                          "https://api.figo.me/assets/images/accounts/postbank.png",
                          {
                            "48x48": "https://api.figo.me/assets/images/accounts/postbank_48.png",
                            "60x60": "https://api.figo.me/assets/images/accounts/postbank_60.png",
                            "72x72": "https://api.figo.me/assets/images/accounts/postbank_72.png",
                            "84x84": "https://api.figo.me/assets/images/accounts/postbank_84.png",
                            "96x96": "https://api.figo.me/assets/images/accounts/postbank_96.png",
                            "120x120": "https://api.figo.me/assets/images/accounts/postbank_120.png",
                            "144x144": "https://api.figo.me/assets/images/accounts/postbank_144.png",
                            "192x192": "https://api.figo.me/assets/images/accounts/postbank_192.png",
                            "256x256": "https://api.figo.me/assets/images/accounts/postbank_256.png"
                          }
                        ]
                  }
                  `
      
              bank := &CatalogBank{}
              err := bank.Unmarshal([]byte(data))
              if err != nil {
                  log.Fatal(err)
              }
              fmt.Printf("advice: %v\n", bank.Advice)
      
              fmt.Printf("icon: %v\n", bank.Icon.URL)
              for size, icon := range bank.Icon.BySize {
                  fmt.Printf("%v =>  %v\n ",size, icon)
              }
          }
      

      【讨论】:

        【解决方案4】:

        您可以像这样定义您的图标

        主包

        import (
            "fmt"
            "encoding/json"
        )
        
        var testIcon = []byte(`{"icon":[
                                "https://api.figo.me/assets/images/accounts/postbank.png",
                                {
                                    "48x48":"https://api.figo.me/assets/images/accounts/postbank_48.png"
                                }]
                            }`)
        
        func main() {
        
            icon := make(map[string][]interface{})
            err := json.Unmarshal(testIcon, &icon)
            if err != nil {
                panic(err)
            }
        
            fmt.Println(icon)
            // map[icon:[https://api.figo.me/assets/images/accounts/postbank.png map[48x48:https://api.figo.me/assets/images/accounts/postbank_48.png]]]
        
        }
        

        【讨论】:

        猜你喜欢
        • 2014-04-27
        • 1970-01-01
        • 2018-05-16
        • 1970-01-01
        • 1970-01-01
        • 2016-12-04
        • 1970-01-01
        • 1970-01-01
        • 2021-03-13
        相关资源
        最近更新 更多