4 ms·
> I was decoding a large JSON data structure that could > easily have thousands of different fields nested 10+ > levels deep. Go's standard json libr
by sagichmal 13y ago
> I was decoding a large JSON data structure that could
> easily have thousands of different fields nested 10+
> levels deep. Go's standard json library usually
> recommends that you define a struct type to hold the
> result of the decode, tagging field names with the
> `json` annotation. This obviously doesn't work when you
> only care about a few dozen of the several thousand
> possible fields.
Sure it does!
type Response struct {
LevelOne map[string]struct{
LevelTwo map[int]struct{
Value string `json:"eventual_value"`
} `json:"level_two"`
} `json:"level_one"`
}
The response can have way more fields than just the ones you declare in your struct.
- nostrademons 13y agoCompared to the Python version of: response['level_one']['level_two']['eventual_value'] ? I did ignore fields that I wasn't interested in; however, you do at least have to declare all the intermediate structs in the tree. With 10-ish levels of nesting, that's a lot of boilerplate; even in your example with 3 levels, you've still got 6 lines of code for what's a one-liner in Python. It wouldn't be as much of a problem for a production system where you define your data structures once and then expect to amortize them over many, many changes. But I was prototyping, and the point of prototyping is to not spend time on boilerplate that isn't necessary to prove out your concept. A few hundred lines of type declarations just so I could decode JSON isn't exactly convenient.
- sagichmal 13y agoLines of code in type declarations isn't an interesting metric. Type safety, however, is.
- gbog 13y agoSaid otherwise, the python oneliner is likely not what you want, in real life you'd have to check for fields existence, purpose defaults or warn, etc. So you must likely end up with a few kings of code anyways.
- nostrademons 13y agoContext of this thread is prototyping. For prototyping that one-liner is exactly what you want; if the fields don't exist just dump a stack trace and fix your code to use stuff that does exist.
- burntsushi 13y agoI think the solution posed to you is at least much better than what your comment thread started with: defining the entire JSON structure with Go types. Actually, I think it's a lot better. Personally, I'd probably stop there---even if I were prototyping. But, at your insistence, we can keep digging. It's easy to write a polymorphic function that arbitrarily picks out values from a Go `interface{}` value. func lookup(v interface{}, keys ...string) interface{} { switch len(keys) { case 0: return v default: dict, ok := v.(map[string]interface{}) if !ok { panic(fmt.Sprintf("%T is not a dictionary", v)) } return lookup(dict[keys[0]], keys[1:]...) } } And then we can use it like you would in Python: lookup(response, "level_one", "level_two", "eventual_value") This doesn't completely remove the burden of type asserting (unfortunate), but it at least makes nested lookups much easier. Arguably, the nested lookups are probably where the type asserts hurt the most. Full example: http://play.golang.org/p/4tWtqGRgU6 http://play.golang.org/p/4tWtqGRgU6