يمكن أن يبدو العمل مع JSON بسيطًا وواضحًا، لديك بعض البنية، ويمكنك تغييرها إلى JSON - لغة موحدة عامة والعودة إلى بنيتك. حق بسيط؟ ?
حسنًا، نعم، ولكن هذا حتى تواجه بعض السلوكيات الغريبة من وظائف Marshal / Unmarshal.
بدأ كل شيء عندما كنت أحاول قراءة الحمولة المشفرة من رمز JWT، فيما يلي مثال يوضح المشكلة
package main import ( "encoding/json" "fmt" ) type User struct { ID int64 `json:"id"` PostIDs []int64 `json:"post_ids"` } func main() { u := User{ ID: 1, PostIDs: []int64{1, 2, 3}, } b, err := json.Marshal(u) if err != nil { panic(err) } m := make(map[string]interface{}) if err = json.Unmarshal(b, &m); err != nil { panic(err) } userID, ok := m["id"].(int64) fmt.Printf("id: %d\nOk:%t\n", userID, ok) fmt.Println() // spliter postIDs, ok := m["id"].([]int64) fmt.Printf("post_ids: %v\nOk:%t\n", postIDs, ok) }
مجرد تنظيم البنية وإلغاء تنظيمها، لذلك من المتوقع أن تُرجع نفس القيمة!
للأسف لم يحدث هذا، الكود الموجود أعلى المخرجات
// Result id: 0 Ok:false post_ids: [] Ok:false
بمجرد أن رأيت هذا الإخراج، أنا؟ قد تكون المشكلة في تحويلات النوع، لذلك ذهبت للتحقق من الأنواع التي تحتوي عليها هذه الواجهات
fmt.Printf("id: %T\n", m["id"]) fmt.Printf("post_ids: %T\n", m["post_ids"])
// Result id: float64 post_ids: []interface {}
كما نرى، قام JSON بتحليل int64 كـ float64، مما يؤدي إلى حدوث مشكلات عند قراءة البيانات.
هناك في الواقع طريقتان لإصلاح هذه المشكلة
استخدم تأكيدات النوع float64، لاحظ أنه لا يمكن تعيين []interface{} على الفور إلى []float64، لذلك يتعين علينا تكرار كل عنصر وتحويله
// Parse UserID userID, _ := m["id"].(float64) fmt.Printf("id: %f\n", userID) fmt.Println() // spliter // Parse PostIDs postIDsArr, _ := m["post_ids"].([]interface{}) postIDs := make([]int64, len(postIDsArr)) for i, v := range postIDsArr { id, _ := v.(float64) // NOTICE: direct conversion to int64 won't work here! postIDs[i] = int64(id) } fmt.Printf("post_ids: %v\n", postIDs)
// Result id: 1.000000 post_ids: [1 2 3]
تحليلها مرة أخرى إلى البنية
b, err = json.Marshal(m) // m = map[string]interface{} if err != nil { panic(err) } var u2 User if err := json.Unmarshal(b, &u2); err != nil { panic(err) } fmt.Println(u2.ID) fmt.Println(u2.PostIDs)
بالطبع، قد تعتقد، لماذا يجب علينا استخدام الحل 01، أليس الحل 02 أفضل؟
حسنًا، يعتمد الأمر على ذلك، فأنت لا ترغب دائمًا في إنشاء بنية لقراءة سمة واحدة من البنية، لذا فإن الإجابة الصحيحة هي -- ذلك يعتمد!
أعتقد أن هذا كل ما في مقال اليوم، أتمنى أن تتعلم شيئًا جديدًا يا زميلي غوفر؟.
تنصل: جميع الموارد المقدمة هي جزئيًا من الإنترنت. إذا كان هناك أي انتهاك لحقوق الطبع والنشر الخاصة بك أو الحقوق والمصالح الأخرى، فيرجى توضيح الأسباب التفصيلية وتقديم دليل على حقوق الطبع والنشر أو الحقوق والمصالح ثم إرسالها إلى البريد الإلكتروني: [email protected]. سوف نتعامل مع الأمر لك في أقرب وقت ممكن.
Copyright© 2022 湘ICP备2022001581号-3