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

Blu*_*Bot 20 go rabbitmq

string通过一个rabbitmq消息系统.发送之前,

我使用json.Marshal,转换结果string并通过rabbitmq发送.

我转换和发送的结构可以是:(更改了结构的名称和大小,但它无关紧要)

type Somthing1 struct{
   Thing        string    `json:"thing"`
   OtherThing   int64     `json:"other_thing"`
}
Run Code Online (Sandbox Code Playgroud)

要么

type Somthing2 struct{
   Croc        int       `json:"croc"`
   Odile       bool      `json:"odile"`
}
Run Code Online (Sandbox Code Playgroud)

消息完美地作为a 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:
}
Run Code Online (Sandbox Code Playgroud)

这不起作用.在打印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:
}
Run Code Online (Sandbox Code Playgroud)

并尝试编写开关,就像在这个答案中解释的那样: Golang:无法在非接口值上键入开关

switch v := interface{}(input).(type)
Run Code Online (Sandbox Code Playgroud)

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

有任何想法吗?

Jim*_*imB 24

json软件包Unmarshals 的默认类型显示在Unmarshal函数文档中

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
Run Code Online (Sandbox Code Playgroud)

由于您正在解组interface{},因此返回的类型将仅来自该集合.该json包不知道Something1Something2.您需要将map[string]interface{}json对象转换为unmarshaled,或者直接解组为所需的struct类型.

如果您不想从通用接口解压缩数据,或以某种方式标记数据以便您知道期望的类型,您可以迭代地获取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
}
Run Code Online (Sandbox Code Playgroud)

http://play.golang.org/p/Trwd6IShDW


fl0*_*cke 9

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

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

快点'肮脏

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

}
Run Code Online (Sandbox Code Playgroud)

在json之上构建自己的"类型系统"

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

type TypedJson struct{
  Type string 
  Data json.RawMessage
}
Run Code Online (Sandbox Code Playgroud)

元帅:

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

typedThing := TypedJson{"something1", tempJson}
finalJson, _ := json.Marshal(typedThing)
Run Code Online (Sandbox Code Playgroud)

解组:

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
}
Run Code Online (Sandbox Code Playgroud)

使用类型化序列化格式

  • @darthydarth`Type`可以是任何符合标识符的东西(例如,不同的int值).它看起来很奇怪,因为它真的只是一个克服json限制的黑客. (2认同)