Reputation: 4161
I have a fairly large nested JSON object I want to decode. I could decode this to a well defined nested struct, but an alternate solution I've seen is to just decode it to an empty interface.
Functionally, this works fine. But I'm wondering if behind the scenes I'm incurring a performance penalty (reflecting) when I decode the object from JSON and again when I later marshal it to JSON.
Thoughts? Thanks in advance.
Code:
CustomizationData interface{} `json:"customizationData" datastore:"-"`
vs.
CustomizationData struct {
Items []struct {
ID string `json:"id"`
Images []struct {
CustomizationState struct {
Areas []struct {
Height float64 `json:"height"`
ID string `json:"id"`
Left float64 `json:"left"`
Parent struct {
Height float64 `json:"height"`
Left float64 `json:"left"`
Top float64 `json:"top"`
Width float64 `json:"width"`
} `json:"parent"`
Rotation float64 `json:"rotation"`
Text string `json:"text"`
Top float64 `json:"top"`
URL string `json:"url"`
Width float64 `json:"width"`
} `json:"areas"`
BackgroundColor string `json:"backgroundColor"`
IsUserSet bool `json:"isUserSet"`
Orientation float64 `json:"orientation"`
} `json:"customizationState"`
SpaceId string `json:"spaceId"`
} `json:"images"`
ProductId float64 `json:"productId"`
Quantity float64 `json:"quantity"`
Sku string `json:"sku"`
TemplateName string `json:"templateName"`
} `json:"items"`
ShippingAddress struct {
City string `json:"city"`
CountryCode string `json:"countryCode"`
Email string `json:"email"`
FirstName string `json:"firstName"`
LastName string `json:"lastName"`
Line1 string `json:"line1"`
Phone string `json:"phone"`
PostalCode string `json:"postalCode"`
State string `json:"state"`
} `json:"shippingAddress"`
TimeStamp string `json:"timeStamp"`
} `json:"customizationData" datastore:"-"
And potentially more.
Upvotes: 3
Views: 2656
Reputation: 132088
It depends entirely on what you intend on doing with the Unmarshalled data.
If you have nested objects / arrays in your json data, then you will end up with nested interfaces. That means you need to explicitly convert your interfaces to the correct type to access their data. In that case you are far better off using the struct in the second example as you will have your data more easily accessible as in myData.Items[0].CustomizationState.Areas[0].Height
. Doing that with nested interface conversion is going to be a pain.
On the other hand, if you are just outputting this data, for example as a response to a webservice call, then you don't need to know the structure and can just spit it back out.
Personally, I always use the latter.
I assume you are using the awesome service at http://mervine.net/json2struct to convert your json into usable Go structs.
Here is a link showing the difference in ease of access between the two methods. http://play.golang.org/p/OlJJPZcxT7
And for those who want to stay in-page:
var dataz = `{"foo": ["bar", "baz"], "boff": {"foo": "bar", "baz": "boff"}}`
type Dataz struct {
Foo []string `json:"foo"`
Boff struct {
Foo string `json:"foo"`
Baz string `json:"baz"`
} `json:"boff"`
}
func main() {
// Method 1
var d interface{}
json.Unmarshal([]byte(dataz), &d)
fmt.Println(d.(map[string]interface{})["foo"].([]interface{})[0])
// Method 2
var D Dataz
json.Unmarshal([]byte(dataz), &D)
fmt.Println(D.Foo[0])
}
EDIT
Edit based on comment about performance
Thankfully we can test it with built-in Go tools
> go test -bench .
testing: warning: no tests to run
PASS
BenchmarkInterface 300000 6208 ns/op
BenchmarkStruct 500000 3622 ns/op
ok parse 3.773s
It's the difference between handling unmarshalling of 276,000/sec or 161,000/sec. So this will almost certainly not be your bottleneck. :)
Upvotes: 3