Heim  >  Artikel  >  Backend-Entwicklung  >  Erstellen Sie manuell ein JSON-Objekt aus einer Struktur in Golang

Erstellen Sie manuell ein JSON-Objekt aus einer Struktur in Golang

WBOY
WBOYnach vorne
2024-02-12 11:03:081066Durchsuche

Erstellen Sie manuell ein JSON-Objekt aus einer Struktur in Golang

In Golang ist das manuelle Erstellen von JSON-Objekten aus einer Struktur ein häufiger Vorgang. Durch die Konvertierung der Struktur in das JSON-Format können wir sie problemlos für die Netzwerkübertragung oder -speicherung verwenden. In diesem Artikel stellt Ihnen der PHP-Editor Banana vor, wie Sie das integrierte Paket von Golang verwenden, um diese Funktion zu erreichen. Darüber hinaus werden wir untersuchen, wie man mit verschachtelten Feldern in Strukturen umgeht und wie man mit speziellen Feldtypen umgeht. Unabhängig davon, ob Sie Anfänger oder erfahrener Entwickler sind, bietet Ihnen dieser Artikel detaillierte Anleitungen, die Ihnen beim einfachen Erstellen von JSON-Objekten in Golang helfen. Lasst uns beginnen!

Frageninhalt

Ich muss eine Struktur sagen

<code>type Foo struct {
  A string `json:",omitemtpy"
}
</code>

Ich weiß, dass ich es mit so etwas leicht in JSON konvertieren kann

json.Marshal(Foo{})

Es wird eine leere JSON-Zeichenfolge zurückgegeben.

Aber ich muss dieselbe Struktur verwenden, um die JSON-Darstellung der Struktur mit allen im JSON vorhandenen Feldern und „Nullwerten“ zurückzugeben. (Eigentlich ist es eine sehr große Struktur, daher kann ich nicht einfach eine Kopie ohne die Tags behalten)

Was ist der einfachste Weg?

Grundsätzlich muss ich einen JSON-Marshal einer Struktur erstellen, die das JSON-Omitempty-Tag ignoriert.

Diese JSON-Erstellung muss nicht effizient oder leistungsfähig sein.

Für diese Art von Aufgabe hätte ich eine Bibliothek vorgezogen, aber die meisten Bibliotheken, die ich gesehen habe, haben entweder ein spezielles Format erstellt oder omitempty respektiert

Herausgeber:

Wählen Sie https://stackoverflow.com/a/77799949/2187510 als meine Antwort und führen Sie zusätzliche Arbeiten aus, um Standardwerte zuzulassen (unter Verwendung des Codes als Referenz)

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)

Ausgabe:

dup FooWithPtrs:
    {"String":"helloWorld","Int":0,"Bar":null} <nil>

Workaround

Sie können Tags zur Laufzeit nicht ändern, aber Sie können Strukturtypen zur Laufzeit erstellen, indem Sie $$c$$reflect.StructOf() verwenden.

Die Idee besteht also darin, den Strukturtyp zu kopieren, aber die Option ,omitempty<code>,omitempty aus dem JSON-Tag bei der Duplizierung auszuschließen.

Alle Beispiele finden Sie unten auf Go Playground.

Es ist einfacher, als die Leute zuerst denken. Wir müssen es nur rekursiv machen (ein Strukturfeld kann eine andere Struktur sein) und wir sollten uns auf jeden Fall mit Zeigern befassen:

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)
}

Lassen Sie es uns mit diesem Typ testen:

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

Hier ist zunächst die JSON-Ausgabe ohne Typduplizierung:

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

Ausgabe:

Foo:
 {"Bar":{"Baz":{}}} <nil>

Beachten Sie, dass wir die Felder Bar<code>BarBaz und Baz

erhalten haben, weil es sich um Strukturen handelt.

Lassen Sie uns versuchen, Folgendes einzugeben:

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

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

Dies wird ausgegeben:

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

Nicht schlecht! Genau das, was wir wollten!

Aber wir sind noch nicht fertig. Was wäre, wenn wir einen Typ mit einem Strukturzeigerfeld hätten? So:

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

Versuchen Sie es mit dem JSON-Marshalling von Werten wiederholter Typen:

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

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

Ausgabe:

dup FooWithPtrs:
 {"String":"","Int":0,"Bar":null} <nil>
null,但我们也希望它们的字段也出现在输出中。这需要将它们初始化为非 nilWenn die Struktur Zeiger enthält, erscheinen diese Zeiger als null in der JSON-Ausgabe

, aber wir möchten, dass ihre Felder auch in der Ausgabe erscheinen. Dies erfordert die Initialisierung mit Nicht-Null<p>-Werten, damit sie eine Ausgabe erzeugen. </p> <p>Glücklicherweise können wir dies auch durch Reflexion tun: </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>Wir sind gespannt! Sehen wir es uns in Aktion an: </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>Ausgabe: </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> 🎜Nicht schlecht! Es enthält alle Felder! 🎜

Das obige ist der detaillierte Inhalt vonErstellen Sie manuell ein JSON-Objekt aus einer Struktur in Golang. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

Stellungnahme:
Dieser Artikel ist reproduziert unter:stackoverflow.com. Bei Verstößen wenden Sie sich bitte an admin@php.cn löschen