Lors du traitement des données JSON, nous utilisons généralement la fonction json.Unmarshal pour analyser la chaîne JSON dans une structure en langage Go. Cependant, l'appel de la fonction json.Unmarshal dans la fonction UnmarshalJSON peut provoquer une erreur de débordement de pile. En effet, la fonction UnmarshalJSON s'appelle à nouveau lors de l'analyse des données JSON, provoquant une boucle infinie. Pour éviter cela, nous pouvons utiliser la méthode Decode de json.Decoder pour analyser les données JSON au lieu d'appeler directement la fonction json.Unmarshal. Cela garantit que les problèmes de débordement de pile ne se produiront pas et garantit la robustesse et les performances du code.
Je souhaite effectuer quelques étapes supplémentaires pour initialiser mon implémentation UnmarshalJSON
中的数据结构。在该实现中调用 json.Unmarshal(b, type)
, ce qui entraîne naturellement un débordement de pile.
Le décodeur JSON continue d'essayer de trouver s'il existe des personnalisations UnmarshalJSON
实现,然后再次调用 json.Unmarshal
.
Y a-t-il une autre façon de procéder ? Le simple fait d'appeler l'implémentation par défaut sous-jacente ne provoquerait-il pas ce problème ?
Un moyen simple et courant d'éviter/prévenir cela consiste à utiliser le mot-clé type
et à utiliser le type conversion pour transmettre une valeur de ce type (la valeur peut être utilisée si vous avez une valeur primitive, le type la conversion est possible car le nouveau type a le type primitif comme type sous-jacent).
Cela fonctionne car le mot-clé type
crée un nouveau type, et le nouveau type n'aura aucune méthode (il n'héritera pas des méthodes du type de base).
Cela entraînera-t-il une surcharge d'exécution ? Non. Cité de Spécification : Conversion :
Voyons un exemple. Nous en avons un avec les chiffres 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 }
Testez-le :
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)
Sortie (essayez-le sur Go Playground) :
<nil> &{Bob 10} <nil> &{Bob 0}
Bien sûr, la même technique fonctionne également pour les commissaires personnalisés (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)) }
Testez-le :
p = &Person{"Bob", 10} fmt.Println(json.NewEncoder(os.Stdout).Encode(p)) p = &Person{"Bob", -1} fmt.Println(json.NewEncoder(os.Stdout).Encode(p))
Sortie (dans le même exemple Go Playground) :
{"name":"Bob","age":10} <nil> {"name":"Bob","age":0} <nil>
Un problème très similaire se produit lorsque vous utilisez la méthode fmt
的自定义文本表示定义 String() string
pour un package> et que vous souhaitez utiliser la représentation sous forme de chaîne par défaut que vous avez modifiée. En savoir plus ici : Différence entre t et *t
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!