我有一个网络套接字连接,它在 JSON 对象中发送不同类型的消息,我想将内容解组为一些已知的结构。为此,我认为我应该执行以下操作:
步骤 1) 将 JSON 解组为通用 map[string]interface{}
第 2 步)找到我要找的钥匙
第 3 步)尝试将值转换为我的一种类型(失败)
步骤 3 替代)json 编组此值并将其解组到我已知的结构中
如果我尝试使用 myStruct, ok := value.(myType)它会失败,但如果我 json.marshal(value) 然后 json.unmarshal 到 myStruct,它工作得很好。这就是我应该这样做的方式吗?转到 json-> map[string]interface{} -> json -> myStruct 对我来说似乎是多余的。
示例代码:
https://play.golang.org/p/to_0Id_ja9
package main
import (
"encoding/json"
"fmt"
)
type Ping struct {
Ping string `json:"ping"`
}
type Ack struct {
Messages []Message `json:"messages"`
}
type Message string
func main() {
testJSON := []byte(`{"ack":{"messages":["Hi there","Hi again"]}}`)
var myAck = Ack{}
var myMap map[string]interface{}
err := json.Unmarshal(testJSON, &myMap)
if err != nil {
fmt.Println("error unmarshalling: ", err)
}
for k, v := range myMap {
fmt.Printf("key: %s, value: %s \n", k, v)
switch k {
case "ping":
fmt.Println(k, " is a ping", v)
case "ack":
fmt.Println(k, " is an ack containing a message list")
ackjson, err := json.Marshal(v)
if err != nil {
fmt.Println("marshal error: ", err)
}
err = json.Unmarshal(ackjson, &myAck)
if err != nil {
fmt.Println("unmarshal error", err)
} else {
fmt.Println("New ack object: ", myAck)
}
default:
fmt.Printf("%s is of a type (%T) I don't know how to handle", k, v)
}
}
}
Run Code Online (Sandbox Code Playgroud)
一种解决方案是通过将值解组为一个json.RawMessage而不是一个来部分解组数据interface{}
var myMap map[string]json.RawMessage
Run Code Online (Sandbox Code Playgroud)
稍后在仍然需要的 switch 中,您不需要编组。做就是了:
err = json.Unmarshal(v, &myAck)
Run Code Online (Sandbox Code Playgroud)
游乐场: https : //play.golang.org/p/NHd3uH5e7z
您将需要创建一个包含您可能收到的所有密钥的结构,然后解组一次,最后根据哪些密钥nil您可以决定获得哪种数据包。
下面的示例显示了此行为:https ://play.golang.org/p/aFG6M0SPJs
package main
import (
"encoding/json"
"fmt"
"strings"
)
type Ack struct {
Messages []string `json:"messages"`
}
type Packet struct {
Ack * Ack `json:"ack"`
Ping * string `json:"ping"`
}
func runTest(testJSON []byte) {
var p = Packet{}
err := json.Unmarshal(testJSON, &p)
if err != nil {
fmt.Println("error unmarshalling: ", err)
}
if (p.Ack != nil) {
fmt.Println("Got ACK: ", strings.Join(p.Ack.Messages, ", "));
} else if (p.Ping != nil){
fmt.Println("Got PING");
}
}
func main() {
tests := [][]byte{
[]byte(`{"ack":{"messages":["Hi there","Hi again"]}}`),
[]byte(`{"ping": "Are you there?"}`),
}
for _, test := range tests {
runTest(test)
}
}
Run Code Online (Sandbox Code Playgroud)