web-dev-qa-db-fra.com

JSON et gestion des champs non exportés

Y a-t-il une raison technique pour laquelle les champs non exportés ne sont pas inclus par le codage/json? Si ce n'est pas le cas et qu'il s'agit d'une décision arbitraire, pourrait-il y avoir une option supplémentaire de porte dérobée (dites "+") à inclure même si elle n'est pas exportée?

Il est malheureux d'exiger du code client pour exporter pour obtenir cette fonctionnalité, surtout si les minuscules fournissent l'encapsulation ou la décision de marshaler les structures vient beaucoup plus tard que leur conception.

Comment les gens gèrent-ils cela? Il suffit d'exporter tout?

De plus, l'exportation des noms de champs ne rend pas difficile le suivi des idiomes suggérés. Je pense que si un struct X a le champ Y, vous ne pouvez pas avoir de méthode d'accesseur Y (). Si vous souhaitez fournir un accès à l'interface à Y, vous devez trouver un nouveau nom pour le getter et peu importe ce que vous obtiendrez quelque chose de non idiomatique selon http://golang.org/doc/effective_go .html # Getters

60
user1338952

Il y a une raison technique. La bibliothèque json n'a pas le pouvoir d'afficher les champs à l'aide de la réflexion sauf s'ils sont exportés. Un package peut uniquement afficher les champs de types non exportés dans son propre package

Pour faire face à votre problème, vous pouvez créer un type non exporté avec des champs exportés. Json sera démarshal dans un type non exporté s'il lui est transmis sans problème, mais il n'apparaîtra pas dans les documents de l'API. Vous pouvez ensuite créer un type exporté qui incorpore le type non exporté. Ce type exporté aurait alors besoin de méthodes pour implémenter le json.Marshaler et json.Unmarshaler interfaces.

Remarque: tout le code n'est pas testé et peut même ne pas être compilé.

type jsonData struct {
    Field1 string
    Field2 string
}

type JsonData struct {
    jsonData
}

// Implement json.Unmarshaller
func (d *JsonData) UnmarshalJSON(b []byte) error {
    return json.Unmarshal(b, &d.jsonData)
}

// Getter
func (d *JsonData) Field1() string {
    return d.jsonData.Field1
}
92
Stephen Weinberg

La réponse de Stephen est complète. En passant, si tout ce que vous voulez vraiment, ce sont des clés en minuscules dans votre json, vous pouvez spécifier manuellement le nom de la clé comme suit:

type Whatever struct {
    SomeField int `json:"some_field"`
}

De cette façon, le marshaling d'un Whats produit la clé "some_field" pour le champ SomeField (au lieu d'avoir "SomeField" dans votre json).

Si vous êtes déterminé à conserver les champs non exportés, vous pouvez également implémenter l'interface json.Marshaler en définissant une méthode avec la signature MarshalJSON() ([]byte, error). Une façon de le faire est d'utiliser un littéral struct qui a simplement exporté des versions des champs non exportés, comme ceci:

type Whatever struct {
    someField int
}

func (w Whatever) MarshalJSON() ([]byte, error) {
    return json.Marshal(struct{
        SomeField int `json:"some_field"`
    }{
        SomeField: w.someField,
    })
}

Cela peut être un peu lourd, vous pouvez donc également utiliser un map[string]interface{} Si vous préférez:

func (w Whatever) MarshalJSON() ([]byte, error) {
    return json.Marshal(map[string]interface{}{
        "some_field": w.SomeField,
    })
}

Cependant, il convient de noter que le marshaling interface{} A quelques mises en garde et peut faire des choses comme marshal uint64 Sur un flottant, entraînant une perte de précision. (tout le code n'a pas été testé)

58
jorelli