Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/go/7.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Go 解组到接口{},然后执行类型断言_Go_Rabbitmq - Fatal编程技术网

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

Go 解组到接口{},然后执行类型断言,go,rabbitmq,Go,Rabbitmq,我通过rabbitmq消息系统获得一个字符串。在发送之前 我使用json.Marshal,将结果转换为string并发送 兔子 我转换和发送的结构可以:(更改结构的名称和大小,但这不重要) 或 消息以字符串的形式完美地传递并打印出来 在另一端(某些服务器) 到目前为止,一切正常。 现在我尝试将它们转换回结构并断言类型 第一次尝试是: func typeAssert(msg string) { var input interface{} json.Unmarshal([]byte(msg)

我通过rabbitmq消息系统获得一个
字符串。在发送之前

我使用
json.Marshal
,将结果转换为
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:
}
这是行不通的。在解组后打印
输入的类型时
我得到
map[string]接口{}
(?!?)

更奇怪的是,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:
}
还试着写了一个开关,答案如下:

仍然没有成功


有什么想法吗?

中显示了
json
包解组的默认类型

由于您要解组到
接口{}
,因此返回的类型将仅来自该集合。
json
包不知道
Something1
Something2
。您需要将json对象解包到的
map[string]接口{}
转换为所需的结构类型

如果您不想从通用接口解包数据,或者不想以某种方式标记数据以便知道所需的类型,那么可以迭代地获取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与类型化语言问题! 由于json是非类型化和无模式的,如果不对其进行实际解码,就无法推断“字符串下”的数据是什么

因此,您唯一的选择是将其解组到一个
接口{}
,该接口总是生成一个
map[string]接口{}
。您可以在这里使用一些反射魔法来构建最终的结构,但这需要大量的手工工作,而且容易出错。 以下是一些可能的解决方案:

快脏 让
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
}
使用类型化序列化格式
  • Go自己的编码
  • 还有更多

这是我的问题,我不知道我得到的是什么类型的字符串。所以secound选项并不好。关于第一个,如果我不知道使用哪个键,我如何转换
map[string]接口{}
@JimB@darthydarth:你说的“线下”是什么意思?在地图上?play.golang.org/p/0zz8fsmo17编辑:很抱歉,在查看您的游乐场解决方案之前,刚刚发表了评论。这正是我错过的!非常感谢。请将其作为解决方案发布给其他人,我将投票表决。再次感谢@JimB@darthydarth:您没有获得结构,当解组到
接口{}
时,您只能获得这6种默认类型中的一种,并且您不能将接口断言为它不是的类型。从正在获取的映射中取出数据,并创建所需类型的新结构。@darthydarth:a仅声明接口中包含特定类型;无法更改它包含的类型。range语句没有改变任何东西,它只是一种显示地图内容的简单方法。喜欢第一种解决方案,它与您命名的完全一样……但仍然可以完美地完成这项工作。第二个不是那么实用,因为在现实生活中,我有一个非常大的结构,它是由程序中许多地方使用的许多其他复杂结构构造而成的,因此仅为命名传输的主结构而构造一个结构对我来说似乎是错误的,一点也不漂亮。@darthydarth这个“包装结构”将仅用于发送和接收数据。您仍然可以在程序中使用原始结构。我认为这是更好的解决方案,但您当然可以自由选择最适合您的情况。我确实在某种程度上同意,但在我看来,在字符串中指定类型仍然很奇怪。在那件事上我可能错了。尽管如此,还是要感谢这两种解决方案-upvoted@darthydarth
类型
可以是任何符合标识符条件的内容(例如,不同的int值)。这看起来很奇怪,因为它实际上只是一种绕过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

}
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
}