كيف تجتاز مقابلة Go: أهم الأسئلة والإجابات

مدرب بايثون أونلاين للمبتدئين

تعلم Python بسهولة دون إرهاق نظري. حل مهام عملية مع التحقق التلقائي واكتب الكود مباشرة في المتصفح.

ابدأ الدورة

كيف تجتاز مقابلة Go: أفضل الأسئلة مع أمثلة الكود



مقابلة مطور Go ليست مجرد اختبار للصياغة، بل هي اختبار للفهم العميق لنموذج التزامن، وإدارة الذاكرة، والأسلوب الاصطلاحي للغة. في هذه المقالة، قمنا بتحليل أفضل 10 أسئلة التي تُطرح غالبًا في مقابلات Golang، مع إجابات مفصلة وأمثلة كود. المادة مناسبة لمستوى Junior و Middle.



1. Goroutines مقابل خيوط نظام التشغيل: ما الفرق؟

هذا سؤال أساسي يختبر فهم نموذج التنفيذ في Go. يجب أن تكون الإجابة واضحة:

  • حجم المكدس: تبدأ الـ Goroutine بمكدس ~2 كيلوبايت ينمو ديناميكيًا. خيط نظام التشغيل له مكدس ثابت (1-8 ميجابايت).
  • تبديل السياق: يتم تبديل الـ Goroutines في مساحة المستخدم (جدولة Go). الخيوط من خلال استدعاء النظام (أكثر تكلفة).
  • تكلفة الإنشاء: تكلفة الـ Goroutine ~4 كيلوبايت من الذاكرة، والخيط ~1 ميجابايت. يمكن تشغيل آلاف الـ Goroutines.
// مثال: 10000 goroutinefunc main() {    for i := 0; i < 10000; i++ {        go func(n int) {            fmt.Println("Goroutine", n)        }(i)    }    time.Sleep(time.Second)}


2. القنوات: المصفوفة وغير المصفوفة

سؤال لاختبار فهم المزامنة. اشرح الفرق بمثال:

  • قناة غير مصفوفة: الإرسال محظور حتى الاستلام. تضمن التزامن.
  • قناة مصفوفة: الإرسال غير محظور طالما أن المخزن المؤقت غير ممتلئ. تسمح بالنقل غير المتزامن.
// قناة غير مصفوفةch := make(chan int)go func() { ch <- 42 }()val := <-ch // محظور حتى تصل القيمة

// قناة مصفوفةbufCh := make(chan int, 2)bufCh <- 1 // غير محظورbufCh <- 2 // غير محظور// bufCh <- 3 // محظور - المخزن المؤقت ممتلئ


3. Select ومعالجة القنوات المتعددة

عامل select يسمح بانتظار عدة عمليات على القنوات. غالبًا ما يُسأل عن default و المهلات الزمنية:

func main() {    ch1 := make(chan string)    ch2 := make(chan string)

go func() { time.Sleep(2 * time.Second); ch1 <- "from ch1" }() go func() { time.Sleep(1 * time.Second); ch2 <- "from ch2" }()

select { case msg := <-ch1: fmt.Println(msg) case msg := <-ch2: fmt.Println(msg) case <-time.After(3 * time.Second): fmt.Println("مهلة زمنية") }}


4. الواجهات: الواجهة الفارغة و type assertion

اختبار فهم interface{} (any) والتحويل الآمن للأنواع:

func describe(i interface{}) {    switch v := i.(type) {    case int:        fmt.Printf("عدد صحيح: %d", v)    case string:        fmt.Printf("سلسلة نصية: %s", v)    default:        fmt.Printf("نوع غير معروف: %T", v)    }}

func main() { describe(42) describe("hello") describe(3.14)}


5. إدارة الذاكرة: المكدس والكومة، تحليل الهروب

سؤال لاختبار فهم كيفية تحديد Go لمكان تخزين المتغيرات. النقطة الأساسية هي تحليل الهروب:

  • إذا رأى المترجم أن المتغير قد يُستخدم بعد العودة من الدالة، فإنه "يهرب" إلى الكومة.
  • استخدام المؤشرات والواجهات والإغلاقات غالبًا ما يسبب تخصيصًا في الكومة.
// المتغير x "يهرب" إلى الكومةfunc createPointer() *int {    x := 42    return &x // x لا يمكن أن يكون على المكدس}


6. Defer: ترتيب التنفيذ والخصائص

يتم تنفيذ Defer وفقًا لمبدأ LIFO (Last In, First Out). يتم حساب الوسائط في وقت التصريح، وليس التنفيذ:

func main() {    x := 10    defer                

المدونات

توصيات الكتب