مقدمة: سؤال يقلق كل مطور Go
\nإذا كنت قد كتبت كودًا بلغة Go من قبل، فبالتأكيد واجهت مهمة تبدو بسيطة للوهلة الأولى: التحقق مما إذا كانت السلسلة النصية فارغة أم لا. قد يبدو الأمر سهلاً، ولكن كما يوضح السؤال الأكثر شهرة على Stack Overflow (بعشرات الآلاف من المشاهدات!)، حتى في هذه العملية البسيطة هناك تفاصيل دقيقة.
\nفي Go، السلاسل النصية ليست مجرد تسلسل من الأحرف. إنها هياكل بيانات معقدة، وفهم بنيتها الداخلية يمكن أن يؤثر بشكل كبير على أداء وقراءة كودك. في هذا المقال، لن نقدم لك إجابة جاهزة فحسب، بل سننظر "تحت الغطاء" في Go، ونحلل كيفية عمل السلاسل النصية، ونكتشف أخيرًا أي طريقة لفحص السلسلة الفارغة هي الأفضل.
\nهل أنت مستعد؟ هيا بنا! 🚀
\n\nما هي السلسلة النصية في Go؟ نظرة تحت الغطاء
\nقبل أن نتحدث عن فحص الفراغ، دعنا نفهم ما هي السلسلة النصية في Go. على عكس العديد من اللغات الأخرى، السلسلة النصية في Go هي تسلسل غير قابل للتغيير (immutable) من البايتات. لكن الشيء الأكثر إثارة للاهتمام هو كيفية تخزينها في الذاكرة.
\n\nرأس السلسلة (String Header): الهيكل الذي لا تراه
\nداخليًا، تمثل Go السلسلة النصية كهيكل بيانات صغير يسمى رأس السلسلة (string header). في الكود، يبدو الأمر كالتالي:
\ntype StringHeader struct {\n Data uintptr // مؤشر إلى مصفوفة البايتات\n Len int // طول السلسلة بالبايتات\n}\nهذا يعني أن أي سلسلة نصية، حتى الفارغة، تشغل 16 بايت (على نظام 64 بت) — 8 بايت للمؤشر و8 بايت للطول. هام: السلسلة الفارغة ليست nil! إنها كائن كامل بمؤشر (عادةً إلى كتلة ذاكرة فارغة خاصة) وطول يساوي صفرًا.
\n\nكيف يؤثر هذا على الفحص؟
\nبمعرفة ذلك، يمكننا فهم كيفية عمل طرق الفحص المختلفة. عندما تكتب s == ""، لا يقوم مترجم Go بمقارنة كل بايت. بل يقوم بما يسمى "مقارنة الرؤوس بشكل فعلي". يقارن حقلين: الطول والمؤشر. إذا تطابق الحقلان، تعتبر السلاسل متساوية. بالنسبة للسلسلة الفارغة، هذا يعني مقارنة Len = 0 و Data = &emptyStringData.
والآن دعنا ننظر إلى len(s) == 0. الدالة len() للسلاسل النصية ليست استدعاء دالة، بل هي عملية مدمجة. يقوم مترجم Go ببساطة بقراءة حقل Len من رأس السلسلة. هذه تعليمة معالج واحدة: MOV (نقل القيمة).
ثلاث طرق للفحص: الخرافات والواقع
\nعلى Stack Overflow، ستجد ثلاثة طرق رئيسية. دعنا نحلل كل منها من حيث الأداء والأسلوب.
\n\n1. len(s) == 0 — الطريقة "التقليدية"
\nكيف تعمل: تأخذ حقل Len من رأس السلسلة وتقارنه بالصفر.
المزايا:
\n- \n
- أعلى أداء. حرفيًا تعليمة أو اثنتين من تعليمات المعالج. لا استدعاءات دوال، ولا مقارنات بايتات. \n
- أسلوب Go الأصيل. مجتمع Go يحب هذه الطريقة لبساطتها وكفاءتها. ستراها كثيرًا في المكتبة القياسية. \n
- واضحة. "إذا كان طول السلسلة يساوي صفرًا، فهذا يعني أن السلسلة فارغة" — منطقي وبديهي. \n
العيوب: قد تبدو أقل قابلية للقراءة من s == "" للمبتدئين.
2. s == "" — الطريقة "الطبيعية"
\nكيف تعمل: تقارن رأسين من السلاسل النصية. بالنسبة للسلسلة الفارغة، هذه مقارنة Len = 0 و Data = &emptyStringData.
المزايا:
\n- \n
- بديهية للمبتدئين. هذا ما تكتبه في Python وJavaScript وJava. "إذا كانت السلسلة تساوي فارغة". \n