مقدمة: لماذا يشتاق مبرمجو Python إلى "in" في Go؟
\n\nإذا أتيت إلى Go من عالم Python، فبالتأكيد تتذكر هذا السطر السحري: if "banana" in fruits:. قصير، أنيق، قابل للقراءة. ثم تفتح Go وتسأل نفسك: "هل يحتوي Go على بناء 'if x in' مشابه لـ Python؟" — هذا هو بالضبط السؤال الأكثر شيوعًا على Stack Overflow، الذي جمع آلاف المشاهدات.
ملخص سريع: لا يوجد سكر نحوي مباشر مثل in في Go. لكن هذا لا يعني أن المهمة غير قابلة للحل أو صعبة الحل. على العكس، في Go هناك عدة طرق اصطلاحية للتحقق من الوجود، كل منها فعال وجميل بطريقته الخاصة.
في هذه المقالة، سنستعرض:
\n- \n
- لماذا لا يوجد
inفي Go وكيف أثرت فلسفة اللغة على ذلك؛ \n - كيفية التحقق من وجود عنصر في الشريحة (slice) (بما في ذلك استخدام الدالة الجديدة
slices.Contains)؛ \n - كيف يعمل البحث في الخريطة (map) (ملخص سريع: هذه هي أسرع طريقة)؛ \n
- البحث عن سلسلة فرعية في سلسلة نصية باستخدام
strings.Contains؛ \n - كتابة دالة تغليف عامة خاصة بنا لأسلوب "يشبه Python"؛ \n
- مقارنة أداء الطرق المختلفة. \n
لماذا لا تريد Go "if x in"؟
\n\nGo لغة بسيطة. مبتكروها (روب بايك، كين تومسون، روب غريزمر) تجنبوا عمدًا إثقال بناء الجملة. بدلاً من إضافة كلمة مفتاحية in، اقترحوا استخدام حلقات صريحة وتراكيب مدمجة.
هذا ليس عيبًا، بل ميزة: ترى دائمًا ما يحدث بالضبط. على سبيل المثال، بالنسبة للخريطة، بناء الجملة value, ok := myMap[key] لا يمنحك فقط التحقق من الوجود، بل أيضًا القيمة نفسها — وهذا أقوى من مجرد قيمة منطقية True/False.
الطريقة 1: البحث في الشريحة (الطريقة التقليدية)
\n\nالسيناريو الأكثر شيوعًا. لنفترض أن لديك شريحة من السلاسل النصية، وتحتاج إلى التحقق مما إذا كانت تحتوي على "Go".
\n\nقبل إصدار Go 1.21، كان عليك كتابة حلقة يدويًا:
\n\npackage main\n\nimport "fmt"\n\nfunc contains(slice []string, target string) bool {\n for _, v := range slice {\n if v == target {\n return true\n }\n }\n return false\n}\n\nfunc main() {\n languages := []string{"Python", "Java", "Go", "Rust"}\n if contains(languages, "Go") {\n fmt.Println("تم العثور على Go!")\n }\n}\n\n\nهذا الكود هو Go اصطلاحي. إنه صريح وسريع ومفهوم. بالنسبة للشرائح الصغيرة (حتى 1000 عنصر)، يعمل هذا البحث الخطي بشكل ممتاز.
\n\nالطريقة 1.1: استخدام slices.Contains (Go 1.21+)
\n\nبدءًا من إصدار Go 1.21 (صدر في أغسطس 2023)، ظهرت حزمة slices في المكتبة القياسية مع دالة جاهزة Contains. الآن أصبح كودك موجزًا تقريبًا مثل Python:
package main\n\nimport (\n "fmt"\n "slices"\n)\n\nfunc main() {\n languages := []string{"Python", "Java", "Go", "Rust"}\n if slices.Contains(languages, "Go") {\n fmt.Println("تم العثور على Go! (عبر slices.Contains)")\n }\n}\n\n\nهام: slices.Contains هي دالة عامة (generic). تعمل مع أي نوع يدعم عامل == (سلاسل نصية، أرقام، قيم منطقية، هياكل بدون شرائح/خرائط داخلها).
الطريقة 2: البحث في الخريطة — ملك الأداء
\n\nفي Python، تستخدم in للقواميس، وهذا وقت ثابت O(1). في Go نفس الشيء، لكن بناء الجملة مختلف:
package main\n\nimport "fmt"\n\nfunc main() {\n // إنشاء خريطة كمجموعة (set)\n fruits := map[string]bool{\n "apple": true,\n "banana": true,\n "cherry": true,\n }\n\n if fruits["banana"] {\n fmt.Println("الموجودة موجودة!")\n }\n\n // الطريقة الأصح — مع التحقق من ok\n if _, ok := fruits["orange"]; ok