كيف تجتاز مقابلة Go: أهم الأسئلة من الألف إلى الياء
\n\nمقابلة منصب مطور Go ليست مجرد اختبار للقواعد النحوية. يبحث أصحاب العمل عن مرشحين يفهمون فلسفة اللغة: البساطة، والتزامن، وإدارة الذاكرة الفعالة. في هذا المقال، سنستعرض الأسئلة الرئيسية التي سيُطرح عليك بالتأكيد - من الأساسيات إلى المواضيع المتقدمة مع أمثلة برمجية. استعد باستخدام قائمتنا المرجعية، وستشعر بالثقة.
\n\n1. أساسيات Go: أنواع البيانات، الهياكل، وإدارة الذاكرة
\n\nلنبدأ بالأساسيات. لا مفر منها. يحب المحاورون طرح أسئلة حول الأنواع وسلوكها.
\n\nما هي أنواع البيانات المضمنة في Go؟
\n- \n
- أساسية:
int,float64,string,bool. \n - مجموعة:
array,struct. \n - مرجعية:
slice,map,channel,pointer,function. \n
ما الفرق بين المصفوفة (array) والشريحة (slice)؟
\nالمصفوفة لها طول ثابت يُحدد في مرحلة الترجمة. الشريحة هي هيكل ديناميكي يشير إلى مصفوفة أساسية.
\n// مصفوفة\nvar arr [3]int = [3]int{1, 2, 3}\narr[0] = 10 // صحيح\n\n// شريحة\nslc := []int{1, 2, 3}\nslc = append(slc, 4) // يمكن أن ينمو الطول\n\nسؤال صعب: ماذا يحدث للذاكرة عند استخدام append إذا تم تجاوز سعة الشريحة؟ (الإجابة: Go يخصص مصفوفة جديدة أكبر بمرتين وينسخ البيانات).
كيف تعمل الخريطة (map) في Go؟
\nالخريطة هي جدول تجزئة. ترتيب الاجتياز غير مضمون. عند القراءة من مفتاح غير موجود، يتم إرجاع القيمة الصفرية (مثل 0 لـ int).
m := make(map[string]int)\nm["key"] = 42\nvalue, ok := m["key"] // ok == true إذا كان المفتاح موجودًا\n\n\n2. التزامن: الغوروتينات، القنوات، والميوتكسات
\nهذا هو الموضوع الأهم في Go. لا يمكن اجتياز المقابلة بدونه.
\n\nما هي الغوروتينة (goroutine) وكيف تختلف عن خيط نظام التشغيل؟
\nالغوروتينة هي خيط خفيف الوزن يُدار بواسطة بيئة تشغيل Go. يبدأ مكدس الغوروتينة من 2-4 كيلوبايت (مقابل 1 ميجابايت لخيط نظام التشغيل). تعمل آلاف الغوروتينات على عدة خيوط من نظام التشغيل (نموذج M:N).
\n\nكيف تعمل القنوات؟ أعط مثالاً لنمط تجمع العمال (worker pool).
\nfunc worker(id int, jobs <-chan int, results chan<- int) {\n for j := range jobs {\n results <- j * 2\n }\n}\n\nfunc main() {\n jobs := make(chan int, 100)\n results := make(chan int, 100)\n\n // تشغيل 3 عمال\n for w := 1; w <= 3; w++ {\n go worker(w, jobs, results)\n }\n\n // إرسال المهام\n for j := 1; j <= 5; j++ {\n jobs <- j\n }\n close(jobs)\n\n // جمع النتائج\n for r := 1; r <= 5; r++ {\n <-results\n }\n}\n\n\nما الفرق بين القناة المخزنة مؤقتًا (buffered) وغير المخزنة (unbuffered)؟
\n- \n
- غير مخزنة: يتم حظر المرسل حتى يستلم المستقبل الرسالة. اتصال متزامن. \n
- مخزنة: يتم حظر المرسل فقط عندما يكون المخزن ممتلئًا. اتصال غير متزامن. \n
كيف تتجنب الجمود (deadlock)؟
\nاستخدم select مع مهلة زمنية أو default:
select {\ncase msg := <-ch:\n fmt.Println(msg)\ncase <-time.After(1 * time.Second):\n fmt.Println("timeout")\n}\n\n\n3. الواجهات، الأدوية (generics)، ومعالجة الأخطاء
\nGo ليست لغة برمجة كائنية التوجه بحتة، لكن الواجهات تلعب دورًا رئيسيًا هنا.
\n\nكيف تعمل البرمجة بنمط البط (duck typing) في Go؟
\nالنوع ينفذ الواجهة ضمنيًا إذا كان لديه جميع الطرق المطلوبة. هذا يسمح بكتابة كود مرن.
\ntype Stringer interface {\n String() string\n}\n\ntype User struct {\n Name string\n}\n\nfunc (u User) Str