2014-04-13 8 views
13

Supponiamo di aver scritto il seguente frammento di codice. Codice completo nel parco giochi here per chi è inclinato.Posso usare MarshalJSON per aggiungere campi arbitrari a una codifica json in golang?

type Book struct { 
    Title  string 
    Author  string 
} 

func main() { 
    ms := Book{"Catch-22", "Joseph Heller"} 
    out, err := json.MarshalIndent(ms, "", " ") 
    if err != nil { 
    log.Fatalln(err) 
    } 
    fmt.Println(string(out)) 
} 

Questo codice emette il seguente, esattamente come mi aspetto:

{ 
    "Title": "Catch-22", 
    "Author": "Joseph Heller" 
} 

Supponiamo per un momento ho voluto aggiungere un campo per l'uscita JSON senza includere nel Book struct. Forse un genere:

{ 
    "Title": "Catch-22", 
    "Author": "Joseph Heller", 
    "Genre": "Satire" 
} 

Posso usare MarshalJSON() per aggiungere un campo arbitrario il payload JSON su Marshal()? Qualcosa di simile:

func (b *Book) MarshalJSON() ([]byte, error) { 
    // some code 
} 

Altro answers farmi pensare questo dovrebbe essere possibile, ma sto lottando per capire l'attuazione.

risposta

20

Ecco una risposta migliore della mia precedente.

type FakeBook Book 

func (b Book) MarshalJSON() ([]byte, error) { 
    return json.Marshal(struct { 
     FakeBook 
     Genre string 
    }{ 
     FakeBook: FakeBook(b), 
     Genre: "Satire", 
    }) 
} 

Poiché i campi struct anonimi sono "fuse" (con alcune considerazioni aggiuntive) possiamo utilizzare che per evitare rimappatura i singoli campi. Notare l'uso del tipo FakeBook per evitare la ricorsione infinita che altrimenti si verificherebbe.

Playground: http://play.golang.org/p/21YXhB6OyC

2

Una possibile risposta a questa domanda è una struct letterale (code here), anche se spero in qualcosa di un po 'più generale, che non richiede la rimappatura tutti i campi della struct:

func (b *Book) MarshalJSON() ([]byte, error) { 
    return json.Marshal(struct{ 
     Title string 
     Author string 
     Genre string 
    } { 
     Title: b.Title, 
     Author: b.Author, 
     Genre: "Satire", 
    }) 
} 
0

Marshalling un map è un altro modo per aggirare il problema.

tmap := make(map[string]interface{}) 

tmap["struct"] = struct { 
    StructValue string `json:"struct_value"` 
}{ 
    "Value 02", 
} 

tmap["string"] = "Value 01" 

out, err := json.MarshalIndent(tmap, "", " ") 
if err != nil { 
    log.Fatalln(err) 
} 
fmt.Println(string(out)) 

Questo stamperà:

{ 
    "string": "Value 01", 
    "struct": { 
    "struct_value": "Value 02" 
    } 
} 

Dove si dispone di molti nomi chiave arbitrari questa potrebbe essere una buona soluzione.

Playground: https://play.golang.org/p/Umy9rtx2Ms

Problemi correlati