Dans Golang, créer manuellement des objets json à partir de struct est une opération courante. En convertissant la structure au format json, nous pouvons facilement l'utiliser en transmission réseau ou en stockage. Dans cet article, l'éditeur PHP Banana vous présentera comment utiliser le package intégré de Golang pour réaliser cette fonction. Non seulement cela, nous explorerons également comment gérer les champs imbriqués dans les structures et comment gérer des types spéciaux de champs. Que vous soyez débutant ou développeur expérimenté, cet article vous fournira des conseils détaillés pour vous aider à créer facilement des objets json dans Golang. commençons!
J'ai une structure à dire
<code>type Foo struct { A string `json:",omitemtpy" } </code>
Je sais que je peux facilement le convertir en json en utilisant quelque chose comme ça
json.Marshal(Foo{})
Il renverra une chaîne json vide.
Mais je dois utiliser la même structure pour renvoyer la représentation json de la structure avec tous les champs et "valeurs nulles" présents dans le json. (En fait, c'est une très grande structure, donc je ne peux pas en garder une copie sans les balises)
Quel est le moyen le plus simple ?
En gros, je dois créer un marshal json d'une structure qui ignore la balise json omitempty.
Cette création json n'a pas besoin d'être efficace ou performante.
J'aurais préféré une bibliothèque pour ce genre de tâche, mais la plupart des bibliothèques que j'ai vues créent un format spécial ou respectent l'omitempty
Éditeur :
Choisissez https://stackoverflow.com/a/77799949/2187510 comme réponse et effectuez un travail supplémentaire pour autoriser les valeurs par défaut (en utilisant son code pour référence)
defaultFoo := FoodWithPts{ Str: "helloWorld"} dupFooType := dupType(reflect.TypeOf(defaultFoo)) foo := reflect.Zero(dupFooType).Interface() // New additions defaults, _ := json.Marshal(defaultFoo) json.Unmarshal(defaults, &foo) // overwrites foo with defaults // End New additions data, err := json.Marshal(foo) fmt.Println("dup FooWithPtrs:\n", string(data), err)
Sortie :
dup FooWithPtrs: {"String":"helloWorld","Int":0,"Bar":null} <nil>
Vous ne pouvez pas modifier les étiquettes au moment de l'exécution, mais vous pouvez créer des types de structure au moment de l'exécution en utilisant $$c$$reflect.StructOf().
L'idée est donc de copier le type struct mais d'exclure l'option ,omitempty<code>,omitempty
de la balise JSON dans la duplication.
Vous pouvez retrouver tous les exemples ci-dessous sur Go Playground.
C’est plus facile que ce que les gens pensent au premier abord. Nous devons juste le faire de manière récursive (un champ de structure peut être une autre structure), et nous devons absolument nous occuper des pointeurs :
func dupType(t reflect.Type) reflect.Type { if t.Kind() == reflect.Pointer { return reflect.PointerTo(dupType(t.Elem())) } if t.Kind() != reflect.Struct { return t } var fields []reflect.StructField for i := 0; i < t.NumField(); i++ { sf := t.Field(i) sf.Type = dupType(sf.Type) // Keep json tag but cut ,omitempty option if exists: if tag, _ := strings.CutSuffix(sf.Tag.Get("json"), ",omitempty"); tag == "" { sf.Tag = "" } else { sf.Tag = `json:"` + reflect.StructTag(tag) + `"` } fields = append(fields, sf) } return reflect.StructOf(fields) }
Testons-le avec ce type :
type Foo struct { Str string `json:"String,omitempty"` Int int `json:",omitempty"` Bar struct { Float float64 `json:",omitempty"` PtrInt int `json:",omitempty"` Baz struct { X int `json:"XXXX,omitempty"` } `json:",omitempty"` } `json:",omitempty"` }
Tout d’abord, voici la sortie JSON sans duplication de type :
data, err := json.Marshal(Foo{}) fmt.Println("Foo:\n", string(data), err)
Sortie :
Foo: {"Bar":{"Baz":{}}} <nil>
Notez que nous obtenons les champs Bar<code>Bar
和 Baz
et Baz</p> car ce sont des structures. <p>
</p>Essayons de taper la copie : <p>
<div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:php;toolbar:false;">dupFooType := dupType(reflect.TypeOf(Foo{}))
foo := reflect.Zero(dupFooType).Interface()
data, err := json.Marshal(foo)
fmt.Println("dup Foo:\n", string(data), err)</pre><div class="contentsignin">Copier après la connexion</div></div>
</p>Cela affichera : <p>
<div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:php;toolbar:false;">dup Foo:
{"String":"","Int":0,"Bar":{"Float":0,"PtrInt":0,"Baz":{"XXXX":0}}} <nil></pre><div class="contentsignin">Copier après la connexion</div></div>
</p>Pas mal ! Exactement ce que nous voulions ! <p>
</p>Mais nous n’avons pas encore fini. Et si nous avions un type avec un champ de pointeur de structure ? Comme ça : <p>
<div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:php;toolbar:false;">type FooWithPtrs struct {
Str string `json:"String,omitempty"`
Int int `json:",omitempty"`
Bar *struct {
Float float64 `json:",omitempty"`
PtrInt int `json:",omitempty"`
Baz *struct {
X int `json:"XXXX,omitempty"`
} `json:",omitempty"`
} `json:",omitempty"`
}</pre><div class="contentsignin">Copier après la connexion</div></div>
</p>Essayez le marshalling JSON des valeurs de types répétés : <p>
<div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:php;toolbar:false;">dupFooType := dupType(reflect.TypeOf(FooWithPtrs{}))
foo := reflect.Zero(dupFooType).Interface()
data, err := json.Marshal(foo)
fmt.Println("dup FooWithPtrs:\n", string(data), err)</pre><div class="contentsignin">Copier après la connexion</div></div>
</p>Sortie : <p>
<div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:php;toolbar:false;">dup FooWithPtrs:
{"String":"","Int":0,"Bar":null} <nil></pre><div class="contentsignin">Copier après la connexion</div></div>
<code>null
,但我们也希望它们的字段也出现在输出中。这需要将它们初始化为非 nil
Si la structure contient des pointeurs, ces pointeurs apparaissent comme null dans la sortie JSON
nil pour qu'ils produisent une sortie.
Heureusement, nous pouvons aussi utiliser la réflexion pour faire ceci :
func initPtrs(v reflect.Value) {
if !v.CanAddr() {
return
}
if v.Kind() == reflect.Pointer {
v.Set(reflect.New(v.Type().Elem()))
v = v.Elem()
}
if v.Kind() == reflect.Struct {
for i := 0; i < v.NumField(); i++ {
initPtrs(v.Field(i))
}
}
}
Copier après la connexion
Nous sommes excités! Voyons-le en action :
dupFooType := dupType(reflect.TypeOf(FooWithPtrs{}))
fooVal := reflect.New(dupFooType)
initPtrs(fooVal.Elem())
data, err := json.Marshal(fooVal.Interface())
fmt.Println("dup and inited FooWithPtrs:\n", string(data), err)
Copier après la connexion
Sortie :
dup and inited FooWithPtrs:
{"String":"","Int":0,"Bar":{"Float":0,"PtrInt":0,"Baz":{"XXXX":0}}} <nil>
Copier après la connexion
🎜Pas mal ! Il contient tous les champs ! 🎜Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!