Heim >Backend-Entwicklung >Golang >Der Aufruf von json.Unmarshal innerhalb der UnmarshalJSON-Funktion führt nicht zu einem Stapelüberlauf

Der Aufruf von json.Unmarshal innerhalb der UnmarshalJSON-Funktion führt nicht zu einem Stapelüberlauf

WBOY
WBOYnach vorne
2024-02-12 08:27:09610Durchsuche

在 UnmarshalJSON 函数内调用 json.Unmarshal 不会导致堆栈溢出

Bei der Verarbeitung von JSON-Daten verwenden wir normalerweise die Funktion json.Unmarshal, um die JSON-Zeichenfolge in eine Struktur in der Go-Sprache zu analysieren. Der Aufruf der json.Unmarshal-Funktion innerhalb der UnmarshalJSON-Funktion kann jedoch zu einem Stapelüberlauffehler führen. Dies liegt daran, dass sich die UnmarshalJSON-Funktion beim Parsen von JSON-Daten erneut aufruft, was zu einer Endlosschleife führt. Um dies zu vermeiden, können wir die Decode-Methode von json.Decoder verwenden, um die JSON-Daten zu analysieren, anstatt die Funktion json.Unmarshal direkt aufzurufen. Dadurch wird sichergestellt, dass keine Stapelüberlaufprobleme auftreten, und die Robustheit und Leistung des Codes wird gewährleistet.

Frageninhalt

Ich möchte einige zusätzliche Schritte ausführen, um meine Implementierung zu initialisieren UnmarshalJSON 中的数据结构。在该实现中调用 json.Unmarshal(b, type), was natürlich zu einem Stapelüberlauf führt.

Der JSON-Decoder versucht ständig herauszufinden, ob es benutzerdefinierte UnmarshalJSON 实现,然后再次调用 json.Unmarshal gibt.

Gibt es eine andere Möglichkeit, dies zu tun? Würde nicht allein der Aufruf der zugrunde liegenden Standardimplementierung dieses Problem verursachen?

Workaround

Eine einfache und übliche Möglichkeit, dies zu vermeiden/verhindern, besteht darin, das Schlüsselwort type zu verwenden und den Typ conversion zu verwenden, um einen Wert dieses Typs zu übergeben (der Wert kann verwendet werden, wenn Sie einen primitiven Wert, den Typ, verwenden Die Konvertierung ist möglich, da dem neuen Typ der primitive Typ als zugrunde liegender Typ zugrunde liegt.

Dies funktioniert, weil das Schlüsselwort type einen neuen Typ erstellt und der neue Typ keine Methoden hat (er „erbt“ nicht die Methoden des Basistyps).

Wird dadurch ein gewisser Laufzeitaufwand entstehen? NEIN. Zitiert aus Spezifikation: Konvertierung:

Sehen wir uns ein Beispiel an. Wir haben eins mit den Zahlen AgePerson 类型,并且我们要确保 Age 不能为负数(小于 0).

type Person struct {
    Name string `json:"name"`
    Age  int    `json:"age"`
}

func (p *Person) UnmarshalJSON(data []byte) error {
    type person2 Person
    if err := json.Unmarshal(data, (*person2)(p)); err != nil {
        return err
    }

    // Post-processing after unmarshaling:
    if p.Age < 0 {
        p.Age = 0
    }
    return nil
}

Testen Sie es:

var p *Person
fmt.Println(json.Unmarshal([]byte(`{"name":"Bob","age":10}`), &p))
fmt.Println(p)

fmt.Println(json.Unmarshal([]byte(`{"name":"Bob","age":-1}`), &p))
fmt.Println(p)

Ausgabe (versuchen Sie es auf Go Playground):

<nil>
&{Bob 10}
<nil>
&{Bob 0}

Die gleiche Technik funktioniert natürlich auch für benutzerdefinierte Marshalls (MarshalJSON()):

func (p *Person) MarshalJSON() ([]byte, error) {
    // Pre-processing before marshaling:
    if p.Age < 0 {
        p.Age = 0
    }

    type person2 Person
    return json.Marshal((*person2)(p))
}

Testen Sie es:

p = &Person{"Bob", 10}
fmt.Println(json.NewEncoder(os.Stdout).Encode(p))
p = &Person{"Bob", -1}
fmt.Println(json.NewEncoder(os.Stdout).Encode(p))

Ausgabe (im selben Go Playground-Beispiel):

{"name":"Bob","age":10}
<nil>
{"name":"Bob","age":0}
<nil>

Ein sehr ähnliches Problem tritt auf, wenn Sie einem Paket eine fmt 的自定义文本表示定义 String() string-Methode hinzufügen und die von Ihnen geänderte Standardzeichenfolgendarstellung verwenden möchten. Lesen Sie hier mehr darüber: Unterschied zwischen t und *t

Das obige ist der detaillierte Inhalt vonDer Aufruf von json.Unmarshal innerhalb der UnmarshalJSON-Funktion führt nicht zu einem Stapelüberlauf. 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