Maison  >  Article  >  développement back-end  >  Créer manuellement un objet json à partir de struct dans golang

Créer manuellement un objet json à partir de struct dans golang

WBOY
WBOYavant
2024-02-12 11:03:081067parcourir

Créer manuellement un objet json à partir de struct dans golang

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!

Contenu de la question

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>

Solution de contournement

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>BarBaz et Baz

car ce sont des structures.

Essayons de taper la copie :

dupFooType := dupType(reflect.TypeOf(Foo{}))
foo := reflect.Zero(dupFooType).Interface()

data, err := json.Marshal(foo)
fmt.Println("dup Foo:\n", string(data), err)

Cela affichera :

dup Foo:
 {"String":"","Int":0,"Bar":{"Float":0,"PtrInt":0,"Baz":{"XXXX":0}}} <nil>

Pas mal ! Exactement ce que nous voulions !

Mais nous n’avons pas encore fini. Et si nous avions un type avec un champ de pointeur de structure ? Comme ça :

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

Essayez le marshalling JSON des valeurs de types répétés :

dupFooType := dupType(reflect.TypeOf(FooWithPtrs{}))
foo := reflect.Zero(dupFooType).Interface()

data, err := json.Marshal(foo)
fmt.Println("dup FooWithPtrs:\n", string(data), err)

Sortie :

dup FooWithPtrs:
 {"String":"","Int":0,"Bar":null} <nil>
null,但我们也希望它们的字段也出现在输出中。这需要将它们初始化为非 nilSi la structure contient des pointeurs, ces pointeurs apparaissent comme null dans la sortie JSON

, mais nous voulons que leurs champs apparaissent également dans la sortie. Cela nécessite de les initialiser à des valeurs non nil<p> pour qu'ils produisent une sortie. </p> <p>Heureusement, nous pouvons aussi utiliser la réflexion pour faire ceci : </p> <pre class="brush:php;toolbar:false;">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 &lt; v.NumField(); i++ { initPtrs(v.Field(i)) } } }</pre> <p>Nous sommes excités! Voyons-le en action : </p> <pre class="brush:php;toolbar:false;">dupFooType := dupType(reflect.TypeOf(FooWithPtrs{})) fooVal := reflect.New(dupFooType) initPtrs(fooVal.Elem()) data, err := json.Marshal(fooVal.Interface()) fmt.Println(&quot;dup and inited FooWithPtrs:\n&quot;, string(data), err)</pre> <p>Sortie : </p> <pre class="brush:php;toolbar:false;">dup and inited FooWithPtrs: {&quot;String&quot;:&quot;&quot;,&quot;Int&quot;:0,&quot;Bar&quot;:{&quot;Float&quot;:0,&quot;PtrInt&quot;:0,&quot;Baz&quot;:{&quot;XXXX&quot;:0}}} &lt;nil&gt;</pre> 🎜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!

Déclaration:
Cet article est reproduit dans:. en cas de violation, veuillez contacter admin@php.cn Supprimer