Encoding/Decoding multi-type fields in JSON?

xuanbao · 2015-06-03 15:19:58 · 929 次点击    
这是一个分享于 2015-06-03 15:19:58 的资源,其中的信息可能已经有所发展或是发生改变。

Hi all, I'd like to en/de/code JSON with Golang which may have multiple types in a given field, something like:

[{"type": "number", "value": 15}, {"type": "string", "value": "Hello!"}]

The "value" field can be string, number, boolean, etc: how to handle this?

edit: I'm grateful for suggestions to use interface{}, but that's a despicable antipattern I'd really rather avoid. Is there any way to achieve this using multiple type-safe fields and JSON annotations to let more than one field map to the same field-name when encoding and decoding?

edit 2: To be more specific, is there some way to do this (except that this doesn't work)?:

type FooStruct struct{
    Type string
    StringValue `json:"value"`
    IntValue `json:"value"`
    FloatValue `json:"value"`
    BooleanValue `json:"value"`
}

**评论:**

ilikeorangutans:

Take a look at RawMessage which lets you delay parsing of parts of the JSON. The example in the docs does pretty much what you are looking for.

cathalgarvey:

This might be my answer, thank you! Needs some experimentation to see how to implement the encoding end robustly but this is a clean-seeming way to handle decoding.

djherbis:

This is a little verbose, but it does what you want. https://play.golang.org/p/ZXudlXBdty

cathalgarvey:

Thank you! This answers my question as to whether the JSON tagging system would suffice, and goes further to provide a working solution. Really cool, thanks.

anhlh2:

I have similar problem but the types and data of possible records are a bit more complex. I found mapstructure and I like it, here is the solution to your question using mapstructure: http://pastebin.com/5Wbzk4ZB

IntellectualReserve:

I haven't found a library I like for this yet. I'm thinking about writing one.

jerf:

Responding to your subsequent edits, interface{} in this case isn't the despicable anti-pattern... it's just a request for encoding/json to use what it uses for interface{}. It isn't truly "unrestricted".

And for edit 2: No. encoding/json is a simple library. It has many weaknesses if you stress it, and you'll have to go find a more complicated library. Among its weaknesses is that it shares something that is true of a lot of static languages with simple JSON libraries, which is that if your JSON is not implicitly a statically-typed document, it has a hard time dealing with that. You'll end up having to do some manual work.

drwiggly:

Made a small wrapper that decodes with raw message and allows path access to the structure of the doc.

https://github.com/chrhlnd/dynjson

That being said depending on what you're doing just decoding with 2 struct types may just be easier.

http://play.golang.org/p/9bPhTY66Gr

cathalgarvey:

Using different types for each value and partially decoding the type hint is actually the cleanest way I've yet seen, thanks. It's a pity things like this either impose convoluted method like this and a runtime cost, or simple, dangerous and still runtime costly methods like interface{}

JHunz:

The struct you decode into should define the value field as an interface{}. Then once you determine the type via the other field, do a runtime cast into a new variable of the appropriate type.

switch decoded.Type {
case "number":
intValue, ok := decoded.Value.(int)
if !ok {
// Error handling...
}
...


入群交流(和以上内容无关):加入Go大咖交流群,或添加微信:liuxiaoyan-s 备注:入群;或加QQ群:692541889

929 次点击  
加入收藏 微博
暂无回复
添加一条新回复 (您需要 登录 后才能回复 没有账号 ?)
  • 请尽量让自己的回复能够对别人有帮助
  • 支持 Markdown 格式, **粗体**、~~删除线~~、`单行代码`
  • 支持 @ 本站用户;支持表情(输入 : 提示),见 Emoji cheat sheet
  • 图片支持拖拽、截图粘贴等方式上传