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.
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?
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 Age
的 Person
类型,并且我们要确保 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!