Convertir JSON en Go
JSON vers struct Go génère des structs à partir d’un document d’exemple, dans votre navigateur. Chaque champ est exporté et porte un tag json explicite, car encoding/json ignore silencieusement les champs non exportés — un nom de champ en minuscules est la raison la plus courante pour laquelle un struct généré se sérialise en objet vide.
Le document s’arrête trop tôt — il semble tronqué.
^
Comment fonctionne Convertir JSON en Go ?
Trois décisions font qu’un struct Go généré est correct ou silencieusement cassé, et les trois portent sur ce que fait encoding/json à l’exécution plutôt que sur l’apparence du code.
Chaque champ est exporté, et doté d’un tag
Go ne sérialise que les champs exportés. Un struct avec un champ appelé id produit {} à partir de json.Marshal et laisse id à zéro après json.Unmarshal, sans erreur dans les deux cas. Chaque nom est donc mis en majuscule et reçoit un tag json:"…" explicite portant la clé d’origine. Les acronymes suivent le guide de style de Go lui-même : user_id devient UserID, pas UserId, et api_url devient APIURL.
Les champs optionnels sont des pointeurs
Un simple string ne peut pas contenir un null JSON, et il ne peut pas distinguer une clé absente d’une clé vide — les deux arrivent sous la forme "". Un simple int ne peut pas distinguer un count manquant d’un count à zéro. Les champs optionnels et nullables deviennent donc des pointeurs, la seule construction en Go qui préserve cette distinction. Les slices, les maps et interface{} sont déjà nilables, donc on les laisse tels quels plutôt que de leur ajouter une deuxième indirection sans objet.
Les entiers que int ne peut pas contenir deviennent int64
int fait 32 bits sur certaines plateformes. Un identifiant snowflake ou un horodatage en millisecondes le fait déborder, et le bug qui en résulte n’apparaît que sur la plateforme où il est étroit. Les valeurs au-delà de 2,147,483,647 sont émises en int64.
Les unions sont des interface{}, car Go n’a pas de type somme
Un tableau contenant à la fois des chaînes et des nombres n’a aucun type Go qui le décrive. Les générateurs qui en inventent un produisent du code qui échoue au unmarshal ; interface{} est la réponse honnête, et l’endroit où corriger ça est l’API, pas le struct.
La sortie est déjà alignée façon gofmt
Noms, types, tags et commentaires de fin de ligne sont alignés sur des colonnes correspondantes. Sans cela, le premier passage de gofmt en CI produit un diff sur un fichier que personne n’a modifié.
Exemple
[
{ "user_id": 900719925474099, "api_url": "https://x.dev" },
{ "user_id": 12, "api_url": "https://y.dev", "note": "hi" }
]Généré
type User struct {
UserID int64 `json:"user_id"`
APIURL string `json:"api_url"`
Note *string `json:"note,omitempty"` // optional
}Quelles options et quels cas limites Convertir JSON en Go prend en charge ?
| Paramètre | Type | Valeur par défaut | Comportement et cas limites |
|---|---|---|---|
| Paquet | identifiant | main | La clause package en haut du fichier. Définissez-la selon le package dans lequel se trouve le fichier de destination — models, api, internal/store. |
| Pointeurs | booléen | on | Les champs optionnels et nuls deviennent *T, afin qu’une clé absente soit distinguable de la valeur zéro. Désactiver cela rend la struct plus simple et rend les données manquantes invisibles. |
| omitempty | booléen | on | Ajoute ,omitempty aux champs optionnels afin qu’ils disparaissent lors du marshalling. Notez que omitempty supprime aussi une chaîne vide ou une valeur zéro, ce qui explique précisément l’utilité des pointeurs. |
| json.Number | booléen | off | Émet json.Number pour les non-entiers au lieu de float64, en conservant les chiffres littéraux. Utile pour les montants ou les IDs qui arrivent comme des nombres non mis entre guillemets et dépassant la plage exacte de float64. |
| string | type Go | string | Les formats détectés (uuid, date-heure, email, uri) sont notés dans un commentaire plutôt que mappés à un type, car encoding/json ne peut pas analyser un timestamp en time.Time sans un unmarshaller personnalisé. |
| Entier | type Go | int / int64 | int par défaut ; int64 lorsque n’importe quel exemple dépasse 2,147,483,647. Un ID tronqué est un bug qui n’apparaît qu’en production. |
| Nombre | type Go | float64 | Toute valeur avec une partie fractionnaire. Si un entier et un flottant apparaissent dans le même champ à travers les enregistrements, le champ devient float64. |
| Objet imbriqué | type Go | *Named | Promu dans sa propre struct et référencé par pointeur, ce qui évite la copie à l’attribution et permet au champ d’être nul. Les formes identiques partagent une seule struct. |
Questions fréquentes
Pourquoi chaque champ est-il en majuscule alors que mes clés JSON sont en minuscules ?
Parce que encoding/json ne voit que les champs exportés, et qu’exporter en Go signifie une première lettre en majuscule. Un champ en minuscules est ignoré aussi bien par Marshal que par Unmarshal, sans erreur, si bien que le struct compile, s’exécute, et ne fait rien. Le tag json porte la clé d’origine, donc le format de transmission ne change pas.
Ai-je besoin des pointeurs ?
Vous en avez besoin partout où absent et zéro signifient des choses différentes. Un *int à nil signifie que la clé était absente ; un int à 0 pourrait être l’un ou l’autre. Pour un champ comme retry_count ou discount, cette distinction compte généralement. Pour un champ que vous savez toujours présent, c’est du bruit, et désactiver les pointeurs est raisonnable.
Pourquoi mon horodatage est-il une string au lieu d’un time.Time ?
Parce que encoding/json ne parse pas tout seul un horodatage arbitraire en time.Time — il ne gère que RFC 3339, et encore uniquement si le champ est déclaré comme time.Time, ce qui échoue alors brutalement sur tout autre format. Générer du time.Time à partir d’un échantillon produirait un struct qui panique sur le premier enregistrement qui formate une date différemment. Le format détecté est signalé dans un commentaire, pour que vous puissiez faire ce choix en connaissance de cause.
Que fait interface{} dans mon struct ?
Ce champ contenait des types réellement différents d’un échantillon à l’autre — une string dans un enregistrement, un objet dans un autre — et Go n’a aucun type pour exprimer cela. Les alternatives sont un UnmarshalJSON personnalisé, un json.RawMessage que vous décodez plus tard, ou réparer l’API. Un type union généré échouerait simplement au unmarshal.
gofmt va-t-il modifier la sortie ?
Il ne devrait pas. Noms de champs, types, tags et commentaires de fin de ligne sont alignés sur des colonnes correspondantes, ce que gofmt fait à un struct. Si vous trouvez un cas où gofmt produit quand même un diff, c’est un bug qui mérite d’être signalé, pas une préférence de style.
Mon JSON est-il envoyé ?
Non. Le parsing, l’inférence de types et le rendu s’exécutent tous dans votre navigateur. Rien n’est envoyé nulle part, ce qui compte car les échantillons que les gens collent dans un générateur de structs sont généralement de vraies réponses d’API d’un système auquel ils s’intègrent.
Quels outils liés devriez-vous utiliser ensuite ?
- Convertir JSON en CSVTransforme des enregistrements en feuille de calcul, imbrications comprises
- Convertir CSV en JSONLit un export de feuille de calcul, guillemets compris
- Sérialiser du JSONÉchappe un document en chaîne prête à intégrer
- Récupérer du JSON échappéRetrouve un document noyé dans les séquences d’échappement