解组到接口{},然后执行类型断言 [英] Unmarshaling Into an Interface{} and Then Performing Type Assertion
问题描述
我通过 rabbitmq 消息系统得到一个 string
.发送前,
I get a string
through a rabbitmq message system. Before sending,
我使用 json.Marshal
,将结果转换为 string
并发送rabbitmq.
I use json.Marshal
, convert the outcome to string
and send through
rabbitmq.
我转换和发送的结构可以是:(更改了结构的名称和大小,但没关系)
The structs that I convert and send can be: (changed the names and the size of the structs but it should not matter)
type Somthing1 struct{
Thing string `json:"thing"`
OtherThing int64 `json:"other_thing"`
}
或
type Somthing2 struct{
Croc int `json:"croc"`
Odile bool `json:"odile"`
}
消息以 string
的形式完美传递并被打印出来在另一端(某些服务器)
The message goes through perfectly as a string
and is printed
on the other side (some server)
到目前为止,一切正常.现在我正在尝试将它们转换回它们的结构并断言类型.
Up until now everything works. Now I'm trying to convert them back into their structs and assert the types.
第一次尝试是:
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:
}
这不起作用.在 Unmarshaling 后打印 input
的类型时我得到 map[string]interface{}
(?!?)
This does not work. When Printing the type of input
after Unmarshaling
it I get map[string]interface{}
(?!?)
更奇怪的是,map key 是我得到的字符串,map value 是空的.
and even stranger than that, the map key is the string I got and the map value is empty.
我做了一些其他的尝试,比如:
I did some other attempts like:
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:
}
并且还尝试编写开关,就像在这个答案中解释的那样:Golang:无法在非接口值上输入开关
and also tried writing the switch like was explained in this answer: Golang: cannot type switch on non-interface value
switch v := interface{}(input).(type)
还是没有成功...
有什么想法吗?
推荐答案
json
包 Unmarshals 成的默认类型显示在 Unmarshal
函数文档
The default types that the json
package Unmarshals into are shown in the Unmarshal
function documentation
bool, for JSON booleans
float64, for JSON numbers
string, for JSON strings
[]interface{}, for JSON arrays
map[string]interface{}, for JSON objects
nil for JSON null
由于您要解组到 interface{}
,因此返回的类型将仅来自该集合.json
包不知道 Something1
和 Something2
.您需要从 json 对象被解组到的 map[string]interface{}
进行转换,或者直接解组到您想要的结构类型.
Since you're unmarshaling into an interface{}
, the returned types will only be from that set. The json
package doesn't know about Something1
and Something2
. You either need to convert from the map[string]interface{}
that the json object is being unmarshaled into, or unmarshal directly into the struct type you want.
如果您不想从通用接口解包数据,或者以某种方式标记数据以便知道预期的类型,则可以迭代地获取 json 并尝试将其解组为您想要的每种类型.
If you don't want to do unpack the data from a generic interface, or somehow tag the data so you know what type to expect, you could iteratively take the json and try to unmarshal it into each type you want.
您甚至可以将它们打包到一个包装器结构中来为您进行解组:
You can even pack those into a wrapper struct to do the unmarshaling for you:
type Something1 struct {
Thing string `json:"thing"`
OtherThing int64 `json:"other_thing"`
}
type Something2 struct {
Croc int `json:"croc"`
Odile bool `json:"odile"`
}
type Unpacker struct {
Data interface{}
}
func (u *Unpacker) UnmarshalJSON(b []byte) error {
smth1 := &Something1{}
err := json.Unmarshal(b, smth1)
// no error, but we also need to make sure we unmarshaled something
if err == nil && smth1.Thing != "" {
u.Data = smth1
return nil
}
// abort if we have an error other than the wrong type
if _, ok := err.(*json.UnmarshalTypeError); err != nil && !ok {
return err
}
smth2 := &Something2{}
err = json.Unmarshal(b, smth2)
if err != nil {
return err
}
u.Data = smth2
return nil
}
http://play.golang.org/p/Trwd6IShDW
这篇关于解组到接口{},然后执行类型断言的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!