2014-07-16 40 views
12

Il problema che sto cercando di risolvere è che ho un modello di una comunità che assomiglia a questoUna struct con molteplici rappresentazioni JSON in Golang

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

Comunità in possesso di un sacco di informazioni e ci sono scenari quando Voglio restituire solo parte della descrizione, ad esempio se restituisco un elenco di community di tendenza. In questo caso avrei voluto restituire solo

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

L'unico modo che posso pensare di fare questo è quello di creare un nuovo tipo che contiene solo quei campi e scrivere un metodo comodo che prende una comunità e restituisce quel tipo, ma essenzialmente creando un nuovo oggetto e copiando quei campi in base al valore, c'è un modo migliore per farlo?

Sono a conoscenza della sintassi json:"-", ma non sono sicuro di come si possa fare questo caso per caso, poiché a volte devo ancora restituire l'intero oggetto, forse un tipo diverso che è tipizzato in ?

+0

Un modo possibile è quello di implementare una consuetudine http://golang.org/pkg/encoding/json/#Marshaler insieme ad un campo di configurazione interna per specificare quali campi della tua struct vuoi emettere –

risposta

2

ho sviluppato una libreria che può aiutare in questo senso: Sheriff

È possibile annotare i vostri campi struct con tag speciali e chiamare lo sceriffo di trasformare il data struct in un sottoinsieme di esso.Dopodiché puoi chiamare lo json.Marshal() o qualsiasi altra cosa tu voglia fare.

Il vostro esempio sarebbe diventato il più semplice:

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

Sì, questo è l'unico modo che conosco utilizzando il Marshaller predefinito. L'unica altra opzione è se crei il tuo 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

Modifica la mia risposta - trovato un modo migliore:

Questo è un approccio fresco:

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

comporta la creazione di una sorta di mascheramento struct.

Ecco l'esempio in questo articolo:

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

io gli presenteremo un altro approccio che ho sviluppato. Penso che sia molto più pulito. L'unico svantaggio è l'inizializzazione degli oggetti leggermente complicata, ma nell'uso è molto snella.

Il punto principale è che non stai basando la tua JSON-view-oggetto per l'oggetto originale e poi nascondere elementi in essa, ma il contrario, che lo rende una parte dell'oggetto originale:

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"} 

E questo è tutto se hai bisogno di una sola vista, o se le tue opinioni sono gradualmente espanse.

Ma se le vostre opinioni non può essere ereditata, si dovrà ricorrere a una sorta di mixins, in modo da poter fare una visualizzazione combinata da loro:

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} 
} 

Qui ho aggiunto una vista nell'oggetto, ma se vi piace, è possibile creare solo al momento della chiamata Marshal:

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

o anche senza una dichiarazione di tipo preliminare:

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

Questo è un approccio piuttosto interessante. La seconda parte della tua risposta mi ricorda i tratti PHP in un certo senso. –

+0

Un momento interessante è che è possibile modificare l'oggetto originale direttamente attraverso le viste. Forse questo approccio può essere utile anche in qualche altro campo. – user

Problemi correlati