Rumah >pembangunan bahagian belakang >Golang >Memanggil json.Unmarshal dalam fungsi UnmarshalJSON tidak menyebabkan limpahan tindanan

Memanggil json.Unmarshal dalam fungsi UnmarshalJSON tidak menyebabkan limpahan tindanan

WBOY
WBOYke hadapan
2024-02-12 08:27:09658semak imbas

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

Apabila memproses data JSON, kami biasanya menggunakan fungsi json.Unmarshal untuk menghuraikan rentetan JSON ke dalam struktur dalam bahasa Go. Walau bagaimanapun, memanggil fungsi json.Unmarshal dalam fungsi UnmarshalJSON boleh menyebabkan ralat limpahan tindanan. Ini kerana fungsi UnmarshalJSON memanggil dirinya semula apabila menghuraikan data JSON, menyebabkan gelung tak terhingga. Untuk mengelakkan ini, kita boleh menggunakan kaedah Nyahkod json.Decoder untuk menghuraikan data JSON dan bukannya memanggil fungsi json.Unmarshal secara langsung. Melakukan ini memastikan bahawa masalah limpahan tindanan tidak akan berlaku dan memastikan keteguhan dan prestasi kod.

Kandungan soalan

Saya ingin melakukan beberapa langkah tambahan untuk memulakan pelaksanaan saya UnmarshalJSON 中的数据结构。在该实现中调用 json.Unmarshal(b, type) yang secara semula jadi mengakibatkan limpahan tindanan.

Penyahkod JSON terus mencuba untuk mencari jika ada tersuai UnmarshalJSON 实现,然后再次调用 json.Unmarshal.

Adakah ada cara lain untuk melakukan ini? Bukankah hanya memanggil pelaksanaan lalai yang mendasari menyebabkan masalah ini?

Penyelesaian

Cara mudah dan biasa untuk mengelakkan ini/mencegah ini adalah dengan menggunakan kata kunci type dan gunakan jenis penukaran untuk lulus nilai jenis itu (nilai boleh digunakan jika anda nilai primitif, penukaran jenis adalah mungkin kerana jenis baharu mempunyai jenis primitif sebagai jenis asasnya).

Ini berfungsi kerana kata kunci type mencipta jenis baharu dan jenis baharu akan mempunyai kaedah sifar (ia tidak akan "mewarisi" kaedah jenis asas).

Adakah ini memerlukan overhed masa jalan? tidak. Dipetik daripada Spesifikasi: Penukaran:

Mari kita lihat contoh. Kami ada satu dengan nombor 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
}

Uji:

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)

Output (cuba di Go Playground):

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

Sudah tentu, teknik yang sama juga berfungsi untuk marshal tersuai (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))
}

Uji:

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

Output (dalam contoh Go Playground yang sama):

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

Masalah yang hampir sama ialah apabila anda menambah kaedah fmt 的自定义文本表示定义 String() string pada pakej a> dan anda mahu menggunakan perwakilan rentetan lalai yang anda ubah suai. Baca lebih lanjut mengenainya di sini: Perbezaan antara t dan *t

Atas ialah kandungan terperinci Memanggil json.Unmarshal dalam fungsi UnmarshalJSON tidak menyebabkan limpahan tindanan. Untuk maklumat lanjut, sila ikut artikel berkaitan lain di laman web China PHP!

Kenyataan:
Artikel ini dikembalikan pada:stackoverflow.com. Jika ada pelanggaran, sila hubungi admin@php.cn Padam