英文:
Is it bad practice in Go to json.Decode a json object to an empty interface?
问题
我有一个相当大的嵌套JSON对象需要解码。我可以将其解码为一个定义良好的嵌套结构,但我看到的另一种解决方案是将其解码为空接口。
从功能上讲,这样做是可以的。但我想知道在幕后当我从JSON解码对象时,以及稍后将其编组为JSON时,是否会产生性能损耗(反射)。
你有什么想法?提前感谢。
代码:
CustomizationData interface{} `json:"customizationData" datastore:"-"`
对比:
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:"-"`
可能还有更多的代码。
英文:
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.
答案1
得分: 3
这完全取决于你对非解组数据的处理意图。
如果你的 JSON 数据中有嵌套的对象/数组,那么你将得到嵌套的接口。这意味着你需要显式地将接口转换为正确的类型以访问它们的数据。在这种情况下,最好使用第二个示例中的结构体,因为你可以更轻松地访问你的数据,例如 myData.Items[0].CustomizationState.Areas[0].Height
。使用嵌套接口转换来做这个将会很麻烦。
另一方面,如果你只是将这些数据输出,例如作为对 Web 服务调用的响应,那么你不需要知道结构,只需将其原样输出即可。
就个人而言,我总是使用后者。
我假设你正在使用 http://mervine.net/json2struct 这个很棒的服务将你的 JSON 转换为可用的 Go 结构体。
这里有一个链接展示了两种方法之间访问数据的便捷性的差异。
http://play.golang.org/p/OlJJPZcxT7
对于那些想要保持在页面内的人:
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() {
// 方法1
var d interface{}
json.Unmarshal([]byte(dataz), &d)
fmt.Println(d.(map[string]interface{})["foo"].([]interface{})[0])
// 方法2
var D Dataz
json.Unmarshal([]byte(dataz), &D)
fmt.Println(D.Foo[0])
}
编辑
根据关于性能的评论进行编辑
幸运的是,我们可以使用内置的 Go 工具进行测试
> go test -bench .
testing: warning: no tests to run
PASS
BenchmarkInterface 300000 6208 ns/op
BenchmarkStruct 500000 3622 ns/op
ok parse 3.773s
这是处理每秒 276,000 次解组或 161,000 次解组的差异。所以这几乎肯定不会成为你的瓶颈。:)
英文:
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.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论