Maison >développement back-end >Golang >L'appel de json.Unmarshal dans la fonction UnmarshalJSON ne provoque pas de débordement de pile

L'appel de json.Unmarshal dans la fonction UnmarshalJSON ne provoque pas de débordement de pile

WBOY
WBOYavant
2024-02-12 08:27:09611parcourir

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

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.

Contenu de la question

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 ?

Solution

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

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!

Déclaration:
Cet article est reproduit dans:. en cas de violation, veuillez contacter admin@php.cn Supprimer