صيد المفاتيح: كيف لا تضيع في غابة Go map
\nتخيل: أنت تكتب خدمة مصغرة بلغة Go. تحتاج إلى التحقق بسرعة مما إذا كان المستخدم مسجلاً في النظام. تصل إلى map، حيث المفتاح هو معرف المستخدم، والقيمة هي ملفه الشخصي. وهنا يطرح السؤال: هل يوجد هذا المفتاح أصلاً في map؟
\nإذا كنت قادماً من Python أو JavaScript، فأنت معتاد على أن الوصول إلى مفتاح غير موجود قد يلقي استثناءً أو يعيد undefined. في Go الأمر مختلف. لا توجد استثناءات هنا، ولكن هناك آلية أنيقة خاصة بها. وإذا حاولت قراءة قيمة بمفتاح غير موجود، فلن يتعطل Go، بل سيعيد ببساطة القيمة الصفرية لنوع القيمة.
يبدو هذا مريحاً؟ نعم، لكنه أيضاً فخ. كيف تميز بين حالة "المفتاح غير موجود" وحالة "المفتاح موجود لكن قيمته صفرية"؟ لهذا بالضبط يوجد أسلوب اصطلاحي خاص — comma ok idiom. دعنا نفهمه مرة واحدة وإلى الأبد.
\n\nكيف تعمل map في Go: نبذة مختصرة
\nقبل الغوص في عمليات التحقق، دعنا نتذكر ما هي map في Go. هي جدول تجزئة يخزن أزواج مفتاح-قيمة. صيغة التصريح:
\n// التصريح عن map: المفاتيح نصوص، والقيم أعداد صحيحة\nvar scores map[string]int\n\n// تهيئة map فارغة (إلزامي!)\nscores = make(map[string]int)\n\n// أو مباشرة مع بيانات\nscores := map[string]int{\n "Alice": 95,\n "Bob": 87,\n}\nنقطة مهمة: إذا حاولت كتابة قيمة في map غير مهيأة (nil map)، سيتعطل البرنامج مع panic. لا تفعل هذا أبداً!
\n\nالطريقة الرئيسية: الإسناد ذو القيمتين (comma ok idiom)
\nهذه هي الطريقة الأصح والأكثر اصطلاحية للتحقق مما إذا كان المفتاح موجوداً في map في Go.
\nالصيغة كالتالي:
\nvalue, ok := myMap[key]\nهنا:
\n- \n
value— القيمة المقابلة للمفتاح (أو القيمة الصفرية إذا كان المفتاح غير موجود) \n ok— متغير منطقي يساويtrueإذا كان المفتاح موجوداً، وfalseإذا لم يكن موجوداً \n
دعنا نلقي نظرة على مثال كامل:
\npackage main\n\nimport "fmt"\n\nfunc main() {\n // إنشاء map بدرجات الطلاب\n grades := map[string]int{\n "ماريا": 88,\n "بيتر": 92,\n "آنا": 0, // نعم، آنا لديها 0 درجة\n }\n\n // التحقق من المفتاح "بيتر"\n if grade, ok := grades["بيتر"]; ok {\n fmt.Printf("درجة بيتر: %d\\n", grade)\n } else {\n fmt.Println("بيتر غير موجود في القائمة")\n }\n\n // التحقق من المفتاح "إيفان"\n if grade, ok := grades["إيفان"]; ok {\n fmt.Printf("درجة إيفان: %d\\n", grade)\n } else {\n fmt.Println("إيفان غير موجود في القائمة")\n }\n\n // حالة معقدة: المفتاح "آنا" موجود لكن القيمة 0\n if grade, ok := grades["آنا"]; ok {\n fmt.Printf("درجة آنا: %d\\n", grade) // سيطبع: درجة آنا: 0\n }\n}\nلاحظ: بالنسبة لمفتاح "آنا"، سيكون ok مساوياً true، على الرغم من أن القيمة صفرية. لهذا السبب لا يمكن الاعتماد فقط على التحقق من القيمة!
لماذا لا يمكن ببساطة المقارنة مع القيمة الصفرية؟
\nيرتكب العديد من المبتدئين هذا الخطأ. يكتبون شيئاً مثل:
\nif grades["إيفان"] != 0 {\n fmt.Println("إيفان موجود في القائمة!")\n}\nهذا غير صحيح لسببين:
\n- \n
- للأنواع الرقمية: إذا كان إيفان لديه بالفعل درجة 0، فستتجاهله. \n
- للأنواع الأخرى: القيمة الصفرية قد تكون نصاً فارغاً (
"")، أوfalse، أوnil. لن تتمكن من التمييز بين "لا يوجد مفتاح" و"المفتاح موجود لكن القيمة فارغة". \n
الطريقة الوحيدة الموثوقة هي استخدام comma ok idiom.
\n\nالتحقق من وجود المفتاح دون الحصول على القيمة
\nأحياناً تحتاج فقط إلى معرفة ما إذا كان المفتاح موجوداً، دون الحاجة إلى القيمة نفسها