用 golang 解码 PubNub 消息 JSON

Decoding PubNub messages with golang JSON

我一直在尝试解析来自 PubNub 的 JSON 消息,但没有成功:

type PubNubMessage struct {
    body []string
}

[[{"text":"hey"}],"1231212412423235","channelName"]
json: cannot unmarshal array into Go value of type main.PubNubMessage

有没有人知道如何在 golang 中解码如此复杂的类型?

您可以在 PubNubMessage 上定义 UnmarshalJSON 以提供自定义 JSON 反序列化。您可能应该根据自己的目的稍微调整一下,但一般的想法是您只需将此 json 数组解组为一个切片,然后从中获取所有必要的部分。

Playground example这里

简短的回答是,您不能直接将 JSON 非同类类型数组(根据您的示例)解组为 golang 结构。

长答案是你应该为你的 PubNubMessage 类型定义一个 (m *PubNubMessage) UnmarshalJSON([]byte) error method ,它将 JSON 字符串解组为 interface{} 然后使用类型断言来确保预期的格式和填充结构。

例如:

type TextMessage struct {
  Text string
}

type PubNubMessage struct {
  Messages []TextMessage
  Id       string
  Channel  string
}

func (pnm *PubNubMessage) UnmarshalJSON(bs []byte) error {
  var arr []interface{}
  err := json.Unmarshal(bs, &arr)
  if err != nil {
    return err
  }
  messages := arr[0].([]interface{}) // TODO: proper type check.
  pnm.Messages = make([]TextMessage, len(messages))
  for i, m := range messages {
    pnm.Messages[i].Text = m.(map[string]interface{})["text"].(string) // TODO: proper type check.
  }
  pnm.Id = arr[1].(string) // TODO: proper type check.
  pnm.Channel = arr[2].(string) // TODO: proper type check.
  return nil
}

  // ...
  jsonStr := `[[{"text":"hey"},{"text":"ok"}],"1231212412423235","channelName"]`
  message := PubNubMessage{}
  err := json.Unmarshal([]byte(jsonStr), &message)

你的json是一个异构数组。您至少可以将 PubNubMessage 定义为

type PubNubMessage []interface{} 然后使用类型断言访问数据 text:= (message[0].([]interface {})[0].(map[string]interface {}))["text"].(string) 工作示例 https://play.golang.org/p/xhwbE2ora1

type PubNubMessage []json.RawMessagejson.Unmarshal(jsonBlob, &message)之后分别为每个和平'json.Unmarshal(message[0], structured.text)'
https://play.golang.org/p/TJ0DfiweGo

使用 encoding/json 包的替代方法更容易解析具有不同类型值的 JSON 数组。例如,尝试 fastjson。它可以轻松(快速)解析此类数组:

input := `[[{"text":"hey"}],"1231212412423235","channelName"]`

var p fastjson.Parser
v, err := p.Parse(input)
if err != nil {
    log.Fatal(err)
}
a := v.GetArray()
for _, vv := range a {
    switch vv.Type() {
    case fastjson.TypeArray:
        fmt.Printf("array %s\n", vv)
    case fastjson.TypeString:
        fmt.Printf("string %s\n", vv)
    }
}

此外 fastjson 提供了方便的函数,用于仅从 JSON:

获取所需的字段
// get v[0].text as Go byte slice
text := v.GetStringBytes("0", "text")

// get v[2]
channelName := v.Get("2")  // this is the same as v.GetArray()[2]