2013-10-30 64 views
3

JSON解碼我需要指定類型以靈活的方式進行解碼JSON數據,這意味着類型需要在運行時被指定。與彈性類型

考慮這個片斷:http://play.golang.org/p/F-Jy4ufMPz

s := `{"b":[{"x":9},{"x":4}]}` 

var a struct { 
    B []interface{} 
} 
err := json.Unmarshal([]byte(s), &a) 
if err != nil { 
    panic(err) 
} 

fmt.Println(a) 

將產生{[map[x:9] map[x:4]]}。我想解碼到一個特定的(結構)類型的數組而不是[]interface{},而無需在編譯時指定它。

這個現象的原因可能不創建陣列前面? (返回的項目數是未知)

我現在能想到的唯一的辦法是稍後再編碼返回的地圖,並將其解碼爲指定的類型,這可能會造成不必要的處理開銷。

+0

爲什麼不直接解碼爲JSON對象並根據需要進行分配? –

+0

該對象非常大,並且當對象的結構已經在結構中定義時,我想避免代碼重複。 –

+0

何時/如何知道應將哪些類型解碼爲? – ANisus

回答

5

如果在編譯時不指定它,你仍然需要在一些地方指定。

如果JSON數據的檢索之前指定的,你可以簡單地做一個開關的情況下,它解組到您所需的對象。

如果內 JSON數據指定,你可以當元帥的「靈活」的部分爲json.RawMessage來處理它,你已經決定以後有什麼類型的結構是合適的:

package main 

import (
    "encoding/json" 
    "fmt" 
) 

var s = `{"type":"structx", "data":{"x":9,"xstring":"This is structX"}}` 

type JsonStruct struct { 
    Type string 
    Data json.RawMessage 
} 

type StructX struct { 
    X  float64 
    Xstring string 
} 

type StructY struct { 
    Y bool 
} 

func main() { 
    var a *JsonStruct 
    err := json.Unmarshal([]byte(s), &a) 
    if err != nil { 
     panic(err) 
    } 

    switch a.Type { 
    case "structx": 
     // We Unmashal the RawMessage part into a StructX 
     var s *StructX 
     json.Unmarshal([]byte(a.Data), &s) 
     if err != nil { 
      panic(err) 
     } 
     fmt.Println(s) 
    case "structy": 
     // Do the same but for structY 
    } 
} 

Playground

+0

'json.RawMessage'的問題是,我無法確定它包含多少行。我想我需要先用'reflect.SliceOf'創建一個新的片,然後將'RawMessage'解壓到它? –

+0

我不知道爲什麼你需要反思。如果項目的數量對於確定結構很重要,那麼你總是將它解組成一個'[] json.RawMessage'。 json.Unmarshal將爲你填補這一切。 – ANisus

+0

是的,我有點困惑。這就是我最終使用的。這是因爲我的真實數據結構比我發佈的要複雜一點(自定義類型嵌入在數組匿名結構字段中)。 –