解组接口{}然后执行类型断言

时间:2016-02-23 17:05:43

标签: go rabbitmq

我通过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完成并打印出来 在另一边(某个服务器)

到目前为止一切正常。 现在我试图将它们转换回结构并断言类型。

首次尝试是:

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{}(?!?)

甚至比这更奇怪,地图键是我得到的字符串,地图值是空的。

我做了一些其他的尝试,如:

 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: cannot type switch on non-interface value

switch v := interface{}(input).(type)

仍然没有成功......

有什么想法吗?

2 个答案:

答案 0 :(得分:17)

json

}

显示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包不了解Something2map[string]interface{}。您需要从json对象被解组的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 } 转换为,或者直接解组为您想要的结构类型。

如果您不想从通用接口解压缩数据,或以某种方式标记数据以便您知道期望的类型,您可以迭代地获取json并尝试将其解组为您想要的每种类型

你甚至可以将它们打包成一个包装器结构来为你做解组:

use a device or emulator running API level 22 or lower

Unmarshal function documentation

答案 1 :(得分:9)

您遇到了典型的json vs类型语言问题! 由于json是无类型和无模式的,因此无法在不实际解码的情况下推断出“在字符串下”的数据。

因此,您唯一的选择是将interface{}解组为始终生成map[string]interface{}。你可以在这里做一些反思魔法来构建最终的结构,但这是很多手工工作并且容易出错。 以下是一些可能的解决方案:

快速'n'脏

json包做反射的东西。尝试解组到每个预期的类型:

func typeAssert(msg string) {

 var thing1 Something1

 err := json.Unmarshal([]byte(msg), &thing1)
 if err == nil{
    // do something with thing1
    return
 }    

 var thing2 Something2

 err = json.Unmarshal([]byte(msg), &thing2)
 if err == nil{
    // do something with thing2
    return
 }    

 //handle unsupported type

}

在json

之上构建自己的“类型系统”

推迟编码,直到你知道里面是什么。使用此结构作为数据的中间表示:

type TypedJson struct{
  Type string 
  Data json.RawMessage
}

元帅:

thing := Something1{"asd",123}
tempJson, _ := json.Marshal(thing)

typedThing := TypedJson{"something1", tempJson}
finalJson, _ := json.Marshal(typedThing)

解组:

func typeAssert(msg string) {

  var input TypedJson  
  json.Unmarshal([]byte(msg), &input)

  switch input.Type{
  case "something1":
    var thing Something1
    json.Unmarshal(input.Data, &thing)
    queueStatsRes(thing)   
   case "something2":
    var thing Something2
    json.Unmarshal(input.Data, &thing)
    queueStatsRes(thing)
  default:
    //handle unsupported type
}

使用类型化序列化格式