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.
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?
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 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 }
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!