我通过rabbitmq消息系统得到一个string
。在发送之前
我使用json.Marshal
,将结果转换为string
并通过rabbitmq发送。
我转换和发送的结构体可以是:(更改了结构体的名称和大小,但这不重要)
type Somthing1 struct{
Thing string `json:"thing"`
OtherThing int64 `json:"other_thing"`
}
或
type Somthing2 struct{
Croc int `json:"croc"`
Odile bool `json:"odile"`
}
消息以string
的形式完美地通过,并打印在另一面(某个服务器)
到目前为止,一切正常。现在我尝试将它们转换回它们的结构并Assert类型。
第一次尝试是:
func typeAssert(msg string) {
var input interface{}
json.Unmarshal([]byte(msg), &input)
switch input.(type){
case Somthing1:
job := Somthing1{}
job = input.(Somthing1)
queueResults(job)
case Somthing2:
stats := Somthing2{}
stats = input.(Somthing2)
queueStatsRes(stats)
default:
}
这不起作用。当打印input
的类型时,我得到map[string]interface{}
(?!?)
更奇怪的是,map键是我得到的字符串,而map值是空的。
我做了一些其他的尝试,比如:
func typeAssert(msg string) {
var input interface{}
json.Unmarshal([]byte(msg), &input)
switch v := input.(type){
case Somthing1:
v = input.(Somthing1)
queueResults(v)
case Somthing2:
v = input.(Somthing2)
queueStatsRes(v)
default:
}
并且还试着写开关,就像在这个答案中解释的那样:
switch v := interface{}(input).(type)
还是没有成功
有什么想法吗
3条答案
按热度按时间wribegjk1#
json
包解组到的默认类型显示在Unmarshal
函数文档中由于您正在解组到
interface{}
中,因此返回的类型将仅来自该集合。json
包不知道Something1
和Something2
。你要么需要从json对象被解封为的map[string]interface{}
转换,要么直接解封为你想要的结构类型。如果你不想从通用接口中解包数据,或者以某种方式标记数据,这样你就知道需要什么类型,你可以迭代地获取json,并尝试将其解组为你想要的每种类型。
你甚至可以将它们打包到一个 Package 器结构中来为你进行解封:
http://play.golang.org/p/Trwd6IShDW
7ajki6be2#
您遇到了一个典型的json vs类型化语言问题!由于json是无类型和无模式的,因此不可能在不实际解码的情况下推断出“字符串下”的数据。
因此,您唯一的选择是解组为
interface{}
,它始终生成map[string]interface{}
。您可以在这里使用一些反射魔法来构建最终的结构体,但这需要大量的手工操作,而且容易出错。以下是一些可能的解决方案:快速和肮脏
让
json
包完成反射工作。尝试解封为每个预期的类型:在json之上构建自己的“类型系统”
推迟编码,直到你知道里面是什么。使用此结构作为数据的中间表示形式:
元帅:
解除编组:
使用类型化序列化格式
oiopk7p53#
我喜欢这种风格的“消息”类型,它可以解组任何预期的消息。
几个好处:
UnmarshalJSON
。这使得它更可重复使用。我更希望顶层消息有一个显式类型。比如
{"messageType":"Somthing1", "messageData":{...}}
。这将把试错方面从解析中去掉。但您不能总是控制数据源,可能需要求助于它。示例(基于JimB的样本):https://go.dev/play/p/vQfY--lSGmh