4 ms·
Shameless plug: I wrote a "JSON Tagged Union" package for go: https://github.com/benjajaja/jtug https://github.com/benjajaja/jtug Let's you decode something li
by the_gipsy 2y ago
Shameless plug: I wrote a "JSON Tagged Union" package for go: https://github.com/benjajaja/jtug https://github.com/benjajaja/jtug
Let's you decode something like
[
{ "type": "A", "count": 10 },
{ "type": "B", "data": "hello" }
]
into some go like:
type Tag string
const (
A Tag = "A"
B Tag = "B"
)
type StructA struct {
Type Tag `json:"type"`
Count int `json:"count"`
}
type StructB struct {
Type Tag `json:"type"`
Data string `json:"data"`
}
by writing a (subjectively) minimal amount of boilerplate:
type Union = jtug.Union[Tag]
type List = jtug.UnionList[Tag, Mapper]
type Mapper struct{}
func (Mapper) Unmarshal(b []byte, t Tag) (jtug.Union[Tag], error) {
switch t {
case A:
var value StructA
return value, json.Unmarshal(b, &value)
case B:
var value StructB
return value, json.Unmarshal(b, &value)
default:
return nil, fmt.Errorf("unknown tag: \"%s\"", t)
}
}
This shows that now it's possible to use `json.Unmarshal` directly:
var list List
err := json.Unmarshal([]byte(`[
{"type":"A","count":10},
{"type":"B","data":"hello"}
]`), &list)
for i := range list {
switch t := list[i].(type) {
case StructA:
println(t.Count)
case StructB:
println(t.Data)
// etc.
}
}
Of course, it relies on reflection, and is generally not very efficient. If you control the API, and it's going to be consumed by go, then I would just not do tagged unions.