解组为接口{},然后执行类型断言
Unmarshaling Into an Interface{} and Then Performing Type Assertion
我通过 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)
仍然没有成功...
有什么想法吗?
json
包解组到的默认类型显示在 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{}
进行转换,或者直接解组到您想要的结构类型。
如果您不想从通用接口解压缩数据,或者不想以某种方式标记数据以便您知道期望的类型,您可以迭代地获取 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 vs 类型化语言问题!
由于 json 是无类型和无模式的,因此在不实际解码的情况下无法推断出 "under the string" 是什么数据。
所以你唯一的选择是解编成一个 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 system"
推迟编码直到你知道里面是什么。使用此结构作为数据的中间表示:
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自带的gob编码
- Protocol Buffers
- 还有更多...
我通过 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)
仍然没有成功...
有什么想法吗?
json
包解组到的默认类型显示在 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{}
进行转换,或者直接解组到您想要的结构类型。
如果您不想从通用接口解压缩数据,或者不想以某种方式标记数据以便您知道期望的类型,您可以迭代地获取 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 vs 类型化语言问题! 由于 json 是无类型和无模式的,因此在不实际解码的情况下无法推断出 "under the string" 是什么数据。
所以你唯一的选择是解编成一个 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 system"推迟编码直到你知道里面是什么。使用此结构作为数据的中间表示:
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自带的gob编码
- Protocol Buffers
- 还有更多...