2014-07-16 66 views
12
多個JSON表示

我試圖解決的問題是,我有一個社區,看起來像這樣一個結構與Golang

type Community struct { 
    Name string 
    Description string 
    Sources []Source 
    Popularity int 
    FavoriteCount int 
    Moderators []string 
    Children []Community 
    Tracks []Track 
} 

社區持有大量的信息模型,並有場景時我只想返回部分描述,例如,如果我要返回趨勢社區列表。在這種情況下,我只想返回

type Community struct { 
    Name string 
    Description string 
    Popularity int 
    FavoriteCount int 
} 

我能想到這樣做是爲了創建一個僅包含那些字段的新類型,寫一個便捷方法,它需要一個社區,並返回該類型的唯一方法,但實質上創建一個新的對象,並按價值複製這些字段,有沒有更好的方法來做到這一點?

我知道json:"-"的語法,但我不確定你是如何做到這一點的情況下,因爲我仍然需要有時返回完整的對象,也許是一種不同的類型,被類型化爲?

+0

一種可能的方式是實現一個自定義http://golang.org/pkg/encoding/json/#Marshaler連同內部配置字段中指定你想要發出的結構的哪些字段 –

回答

2

我開發了一個庫,它可以幫助你在這方面:Sheriff

您可以用特殊的標記註釋你的結構域和謝里夫打電話給定結構轉化爲它的一個子集。之後,您可以撥打json.Marshal()或其他任何您想要編入的內容。

爲你的榜樣將變得非常簡單:

type Community struct { 
    Name   string  `json:"name" groups:"trending,detail"` 
    Description string  `json:"description" groups:"trending,detail"` 
    Sources  []Source `json:"sources" groups:"detail"` 
    Popularity int   `json:"popularity" groups:"trending,detail"` 
    FavoriteCount int   `json:"favorite_count" groups:"trending,detail"` 
    Moderators []string `json:"moderators" groups:"detail"` 
    Children  []Community `json:"children" groups:"detail"` 
    Tracks  []Track  `json:"tracks" groups:"detail"` 
} 

communities := []Community{ 
    // communities 
} 

o := sheriff.Options{ 
    Groups: []string{"trending"}, 
} 

d, err := sheriff.Marshal(&o, communities) 
if err != nil { 
    panic(err) 
} 

out, _ := json.Marshal(d) 
3

是的,據我所知,使用默認的Marshaller是唯一的方法。唯一的另一種選擇是如果你創建你自己的JsonMarshaller。

type Community struct { 

} 

type CommunityShort Community 

func (key *Community) MarshalJSON() ([]byte, os.Error) { 
    ... 
} 

func (key *Community) UnmarshalJSON(data []byte) os.Error { 
... 
} 


func (key *CommunityShort) MarshalJSON() ([]byte, os.Error) { 
    ... 
} 

func (key *CommunityShort) UnmarshalJSON(data []byte) os.Error { 
... 
} 
12

編輯我的答案 - 找到一個更好的辦法:

這是一個很酷的方法:

http://attilaolah.eu/2014/09/10/json-and-struct-composition-in-go/

涉及到創建一種屏蔽結構的。

這裏的文章中的例子:

type User struct { 
    Email string `json:"email"` 
    Password string `json:"password"` 
    // many more fields… 
} 

type omit *struct{} 

type PublicUser struct { 
    *User 
    Password omit `json:"password,omitempty"` 
} 

// when you want to encode your user: 
json.Marshal(PublicUser{ 
    User: user, 
}) 
2

我將介紹你,我已經開發了另一種方法。我認爲它更乾淨。唯一的缺點是稍微複雜的對象初始化,但在使用中它非常簡化。

主要的一點是,你不是原來的對象上立足的JSON-視圖對象,然後在裏面隱藏元素,但周圍的其他方法,使得它的原始對象的一部分:

type CommunityBase struct { 
    Name string 
    Description string 
} 

type Community struct { 
    CommunityBase 
    FavoriteCount int 
    Moderators []string 
} 

var comm = Community{CommunityBase{"Name", "Descr"}, 20, []string{"Mod1","Mod2"}} 

json.Marshal(comm) 
//{"Name":"Name","Description":"Descr","FavoriteCount":20,"Moderators":["Mod1","Mod2"]} 

json.Marshal(comm.CommunityBase) 
//{"Name":"Name","Description":"Descr"} 

這就是所有如果您只需要一個視圖,或者如果您的意見逐步擴大。

但是如果你的意見不能被繼承,你將不得不求助於一種混入的,這樣就可以使他們從一個組合視圖:

type ThingBaseMixin struct { 
    Name string 
} 

type ThingVisualMixin struct { 
    Color string 
    IsRound bool 
} 

type ThingTactileMixin struct { 
    IsSoft bool 
} 

type Thing struct { 
    ThingBaseMixin 
    ThingVisualMixin 
    ThingTactileMixin 
    Condition string 
    visualView *ThingVisualView 
    tactileView *ThingTactileView 
} 

type ThingVisualView struct { 
    *ThingBaseMixin 
    *ThingVisualMixin 
} 

type ThingTactileView struct { 
    *ThingBaseMixin 
    *ThingTactileMixin 
} 

func main() { 
    obj := Thing { 
     ThingBaseMixin: ThingBaseMixin{"Bouncy Ball"}, 
     ThingVisualMixin: ThingVisualMixin{"blue", true}, 
     ThingTactileMixin: ThingTactileMixin{false}, 
     Condition: "Good", 
    } 
    obj.visualView = &ThingVisualView{&obj.ThingBaseMixin, &obj.ThingVisualMixin} 
    obj.tactileView = &ThingTactileView{&obj.ThingBaseMixin, &obj.ThingTactileMixin} 

    b, _ := json.Marshal(obj) 
    fmt.Println(string(b)) 
//{"Name":"Bouncy Ball","Color":"blue","IsRound":true,"IsSoft":false,"Condition":"Good"} 

    b, _ = json.Marshal(obj.ThingVisualMixin) 
    fmt.Println(string(b)) 
//{"Color":"blue","IsRound":true} 

    b, _ = json.Marshal(obj.visualView) 
    fmt.Println(string(b)) 
//{"Name":"Bouncy Ball","Color":"blue","IsRound":true} 

    b, _ = json.Marshal(obj.tactileView) 
    fmt.Println(string(b)) 
//{"Name":"Bouncy Ball","IsSoft":false} 
} 

在這裏,我增加了一個圖到對象,但如果你喜歡,你可以打電話Marshal只是當創建它:

json.Marshal(ThingVisualView{&obj.ThingBaseMixin, &obj.ThingVisualMixin}) 

甚至沒有一個初步的類型聲明:

json.Marshal(struct{*ThingBaseMixin;*ThingVisualMixin}{&obj.ThingBaseMixin,&obj.ThingVisualMixin}) 
+0

這是一個非常有趣的方法。您的回覆的第二部分以某種方式讓我想起了PHP特性。 –

+0

有趣的是,您可以直接通過視圖編輯原始對象。也許這種方法也可以用於其他領域。 – user