2014-09-25 50 views
0

我正在學習Go通過編寫一個簡單的http服務器,我需要處理一些JSON響應。 structResult:解組頂級JSON數組Go

與對象響應,我可以用2行代碼地道解組它=美孚{} json.Unmarshal(structBody,& structResult)

我不知道怎麼做相同的數組響應(請參閱下面的示例)。有沒有一種方法來指定(可能通過json標籤)頂層數組應該進入給定的結構域?

package main 

import "fmt" 
import "encoding/json" 

type Foo struct { 
    Id uint64 `json:"id"` 
    Name string `json:"name"` 
} 

type BaseResult struct { 
    Error string `json:"error"` 
} 

type FooResult struct { 
    BaseResult 
    Foos []Foo 
} 

func main() { 
    // Simple and works. 
    structBody := []byte(`{"id": 1,"name": "foo"}`) 
    structResult := Foo{} 
    json.Unmarshal(structBody, &structResult) 
    fmt.Printf("%#v\n", structResult) 

    // Doesn't work. 
    arrayBody := []byte(`[{"id": 1,"name": "foo"},{"id": 2,"name": "bar"},{"id": 3,"name": "foobar"}]`) 
    arrayResult := FooResult{} 
    json.Unmarshal(arrayBody, &arrayResult) 
    fmt.Printf("%#v\n", arrayResult) 
} 

我知道我可以做FooResult數組:

type FooResult []Foo 

但後來我失去了指定基本對象,我想用存儲錯誤消息,並且這樣的能力。我也知道我可以直接解組成& fooResult.Foos,但我希望代碼能夠同時處理對象和數組。

UPDATE

實施UnmarshalJSON通過@dyoo的建議部分地解決我的問題,但我希望我可以用BaseResult存儲解析錯誤的情況下,JSON具有不同的結構:

arrayBody := []byte(`{"error": "foo"}`) 
arrayResult := FooResult{} 
json.Unmarshal(arrayBody, &arrayResult) 
fmt.Printf("%#v\n", arrayResult) 

中當然我可以在UnmarshalJSON中實現更復雜的邏輯 - 但是沒有更簡單的方法來實現它嗎?

+0

建議:重命名'FooResult'到'ArrayResult'。使用'Foo'作爲名字的任何部分往往是可疑的,因爲它並不意味着什麼。 – dyoo 2014-09-25 18:16:40

+0

當然,在這個例子中我只使用了名字「foo」。 – proxi 2014-09-26 08:55:14

回答

1

您可以在FooResult中實現json.Unmarshaler接口,以自定義它對解組的響應方式。 (同樣,有一個json.Marshaler接口。)

地址:

func (f *FooResult) UnmarshalJSON(bs []byte) error { 
    return json.Unmarshal(bs, &f.Foos) 
} 

之後,你的代碼應該以其他方式使用。但即使是這樣開始看起來可疑

func (f *FooResult) UnmarshalJSON(bs []byte) error { 
    err1 := json.Unmarshal(bs, &f.BaseResult) 
    err2 := json.Unmarshal(bs, &f.Foos) 
    if err1 != nil && err2 != nil { 
     // Arbitrarily choose an error. 
     return err1 
    } 
    return nil 
} 

http://play.golang.org/p/oMdoB2e-rB

你可以嘗試類似。處理工會類型結果不是什麼json庫設計爲您自動處理。如果您的JSON具有動態類型,則需要顯式編碼強制邏輯。

參見:How to unmarshall an array of different types correctly?http://blog.golang.org/json-and-go的相關問題。

+0

謝謝。這回答了我的問題,但我的問題的真正原因是我希望在返回的JSON具有不同結構(許多API以這種方式封裝)的情況下使用基本結構來存儲錯誤。我想知道這是否可能。 – proxi 2014-09-25 19:34:53

+0

您不需要實現UnmarshalJSON,只需在解組時指定Foos即可。我在下面的答案中有一個例子。 – jmaloney 2014-09-26 00:08:58

0

只要指定Foos當你解組

package main 

import "fmt" 
import "encoding/json" 

type Foo struct { 
    Id uint64 `json:"id"` 
    Name string `json:"name"` 
} 

type BaseResult struct { 
    Error string `json:"error"` 
} 

type FooResult struct { 
    BaseResult 
    Foos []Foo 
} 

func main() { 
    // Simple and works. 
    structBody := []byte(`{"id": 1,"name": "foo"}`) 
    structResult := Foo{} 
    json.Unmarshal(structBody, &structResult) 
    fmt.Printf("%#v\n", structResult) 

    // Doesn't work. 
    arrayBody := []byte(`[{"id": 1,"name": "foo"},{"id": 2,"name": "bar"},{"id": 3,"name": "foobar"}]`) 
    arrayResult := FooResult{} 
    if err := json.Unmarshal(arrayBody, &arrayResult.Foos); err != nil { 
     arrayResult.BaseResult.Error = string(arrayBody) 
    } 

    fmt.Printf("%#v\n", arrayResult) 
} 
+0

謝謝。我知道我可以做到這一點,但我的觀點是保持解析邏輯接近結構,避免爲每種情況編寫代碼。通過UnmarshalJSON @ dyoo的解決方案更好。 – proxi 2014-09-26 09:02:04