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:
cathalgarvey: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.
djherbis: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.
cathalgarvey:This is a little verbose, but it does what you want. https://play.golang.org/p/ZXudlXBdty
anhlh2: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.
IntellectualReserve: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
jerf:I haven't found a library I like for this yet. I'm thinking about writing one.
drwiggly:Responding to your subsequent edits,
interface{}
in this case isn't the despicable anti-pattern... it's just a request forencoding/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.
cathalgarvey: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.
JHunz: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{}
…
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...
}
...
