How to unmarshal from interface{} to interface{} in Go

huangapple go评论78阅读模式
英文:

How to unmarshal from interface{} to interface{} in Go

问题

在我的系统中有多个节点通过RPC进行通信。我试图通过RPC将一个map[string] interface{}发送到另一个节点。发送方使用json.Marshal,接收方使用json.Unmarshal来获取这个map。
假设在发送方的一侧,map包含1 => 2,其中2的类型是uint32。
问题是Unmarshal尝试找到底层数据的类型,并根据其默认行为将2转换为float64类型,如此处所指定的https://blog.golang.org/json-and-go。稍后,将float64转换为uint32会引发恐慌。

我参考了https://stackoverflow.com/questions/28254102/how-to-unmarshal-json-into-interface-in-golang。但是,对于这个问题,我们需要知道数据的类型。在我的情况下,数据可以是任何类型,所以我想将其保持为interface{}。如何从interface{}解组到interface{}?

英文:

There are multiple nodes in my system which communicate through RPC. I am trying to send a map[string] interface{} to another node through RPC. Sender uses json.Marshal and receiver uses json.Unmarshal to get the map.
Let us say at the sender side, map contains 1 => 2 where 2 is of type uint32.
The problem is Unmarshal tries to find the type of underlying data and converts 2 to float64 type according to its default behavior as specified here https://blog.golang.org/json-and-go. Later, casting float64 to uint32 causes panic.

I refered to https://stackoverflow.com/questions/28254102/how-to-unmarshal-json-into-interface-in-golang . But for this, we need to know the type of data. In my case data can be of any type so I want to keep it as interface{}. How do I unmarshal from interface{} to interface{}?

答案1

得分: 5

很遗憾,使用encoding/json包是无法实现的,因为类型信息不会被传输,如果没有类型信息,默认情况下,JSON数字会被解组为float64类型的值。你需要定义struct类型,并明确指定字段的类型为uint32

或者你可以选择使用encoding/gob,它可以传输和保留类型信息。以下是一个示例:

m := map[string]interface{}{"1": uint32(1)}

b := &bytes.Buffer{}
gob.NewEncoder(b).Encode(m)

var m2 map[string]interface{}
gob.NewDecoder(b).Decode(&m2)
fmt.Printf("%T\n%#v\n", m2["1"], m2)

输出结果(在Go Playground上尝试):

uint32
map[string]interface {}{"1":0x1}

gob的缺点是它是Go特定的,不像JSON那样是语言和平台无关的。

英文:

Unfortunately using the encoding/json package you can't, because type information is not transmitted, and JSON numbers by default are unmarshaled into values of float64 type if type information is not present. You would need to define struct types where you explicitly state the field is of type uint32.

Alternatively you may opt to use encoding/gob which does transmit and preserve type information. See this example:

m := map[string]interface{}{"1": uint32(1)}

b := &bytes.Buffer{}
gob.NewEncoder(b).Encode(m)

var m2 map[string]interface{}
gob.NewDecoder(b).Decode(&m2)
fmt.Printf("%T\n%#v\n", m2["1"], m2)

Output (try it on the Go Playground):

uint32
map[string]interface {}{"1":0x1}

The downside of gob is that it's Go-specific unlike the language and platform independent JSON.

huangapple
  • 本文由 发表于 2016年11月27日 05:20:10
  • 转载请务必保留本文链接:https://go.coder-hub.com/40823273.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定