普通网友 2015-02-18 17:57
浏览 54
已采纳

在Go to json中是不好的做法。将json对象解码为空接口吗?

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条回答 默认 最新

  • donqh00404 2015-02-18 18:33
    关注

    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. :)

    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论

报告相同问题?