Maison > développement back-end > Golang > le corps du texte

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

WBOY
Libérer: 2024-02-12 11:03:08
avant
1100 Les gens l'ont consulté

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>
Copier après la connexion

Je sais que je peux facilement le convertir en json en utilisant quelque chose comme ça

json.Marshal(Foo{})
Copier après la connexion

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)
Copier après la connexion

Sortie :

dup FooWithPtrs:
    {"String":"helloWorld","Int":0,"Bar":null} <nil>
Copier après la connexion

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)
}
Copier après la connexion

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"`
}
Copier après la connexion

Tout d’abord, voici la sortie JSON sans duplication de type :

data, err := json.Marshal(Foo{})
fmt.Println("Foo:\n", string(data), err)
Copier après la connexion

Sortie :

Foo:
 {"Bar":{"Baz":{}}} <nil>
Copier après la connexion

Notez que nous obtenons les champs Bar<code>BarBaz 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(&quot;dup Foo:\n&quot;, 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: {&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><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:&quot;String,omitempty&quot;` Int int `json:&quot;,omitempty&quot;` Bar *struct { Float float64 `json:&quot;,omitempty&quot;` PtrInt int `json:&quot;,omitempty&quot;` Baz *struct { X int `json:&quot;XXXX,omitempty&quot;` } `json:&quot;,omitempty&quot;` } `json:&quot;,omitempty&quot;` }</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(&quot;dup FooWithPtrs:\n&quot;, 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: {&quot;String&quot;:&quot;&quot;,&quot;Int&quot;:0,&quot;Bar&quot;:null} &lt;nil&gt;</pre><div class="contentsignin">Copier après la connexion</div></div> <code>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

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!

Étiquettes associées:
source:stackoverflow.com
Déclaration de ce site Web
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn
Tutoriels populaires
Plus>
Derniers téléchargements
Plus>
effets Web
Code source du site Web
Matériel du site Web
Modèle frontal