⏱️3 min read · 614 words
تغطي أسئلة مقابلة Go (Golang) في عام 2026 الإجراءات والقنوات والواجهات وإدارة الذاكرة وأنماط الإنتاج. يتم استخدام Go في Google وCloudflare وDocker وKubernetes ومعظم الشركات السحابية الأصلية. يغطي هذا الدليل الأسئلة الأكثر شيوعًا في مقابلة Go.
مفاهيم الذهاب الأساسية
1. ما الذي يجعل لغة Go مختلفة عن اللغات الأخرى؟
- جوروتينس: سلاسل رسائل خفيفة الوزن (مكدس سعة 2 كيلو بايت مقابل سلاسل عمليات نظام تشغيل بسعة 1 ميجابايت)
- القنوات: أساسيات الاتصال من الدرجة الأولى (“لا تتواصل من خلال مشاركة الذاكرة؛ شارك الذاكرة من خلال التواصل”)
- تجميع سريع: يجمع في ثوان
- ثنائي واحد: مرتبط بشكل ثابت، لا توجد تبعيات وقت التشغيل
- تم جمع القمامة: ولكن مع توقفات GC منخفضة جدًا
- لا ميراث: التكوين عن طريق التضمين والواجهات
2. اشرح goroutines مقابل سلاسل عمليات نظام التشغيل
package main
import (
"fmt"
"runtime"
"sync"
)
func main() {
// OS threads: ~1MB stack, managed by OS
// Goroutines: ~2KB stack (grows as needed), managed by Go runtime
// Can run millions of goroutines on a few OS threads
runtime.GOMAXPROCS(runtime.NumCPU()) // use all CPU cores
var wg sync.WaitGroup
for i := 0; i < 1_000_000; i++ { // 1 million goroutines!
wg.Add(1)
go func(id int) {
defer wg.Done()
// Each goroutine does minimal work
}(i)
}
wg.Wait()
fmt.Println("Done")
}
3. ما الفرق بين القنوات المخزنة وغير المخزنة؟
// Unbuffered: sender blocks until receiver ready
ch := make(chan int)
go func() { ch <- 42 }() // blocks until receive
val := <-ch
// Buffered: sender blocks only when buffer full
buffered := make(chan int, 5)
buffered <- 1 // doesn't block (buffer has space)
buffered <- 2
buffered <- 3
// buffered <- ... (6th send would block)
// Use buffered for:
// - Known number of items to send
// - Decoupling sender/receiver speeds
// - Preventing goroutine leaks in producer patterns
// Use unbuffered for:
// - Guaranteed synchronization
// - Signaling (done channels)
4. كيف تتجنب تسربات الغوروتين؟
// LEAK: goroutine blocks forever on channel
func badWorker() {
ch := make(chan int)
go func() {
// This goroutine will block forever if no one sends to ch!
val := <-ch
process(val)
}()
// ch goes out of scope, goroutine is stuck
}
// FIX: use context for cancellation
func goodWorker(ctx context.Context) {
ch := make(chan int, 1)
go func() {
select {
case val := <-ch:
process(val)
case <-ctx.Done(): // cancelled — exit cleanly
return
}
}()
}
// Always ensure goroutines have a way to exit
// Rules:
// 1. Goroutine started → must have guaranteed exit path
// 2. Use context.Context for cancellation
// 3. Use done channels for signaling completion
// 4. goleak package in tests catches leaks
5. شرح واجهات Go
// Interface: implicit implementation (no "implements" keyword)
type Writer interface {
Write(data []byte) (n int, err error)
}
// Any type with Write method satisfies Writer
type FileWriter struct{ path string }
func (f *FileWriter) Write(data []byte) (int, error) {
// write to file
return len(data), nil
}
type NetworkWriter struct{ conn net.Conn }
func (n *NetworkWriter) Write(data []byte) (int, error) {
return n.conn.Write(data)
}
// Function works with any Writer
func sendData(w Writer, data []byte) error {
_, err := w.Write(data)
return err
}
// Empty interface (any type)
var anything interface{} = 42
anything = "now a string"
anything = struct{ x int }{x: 1}
// Type assertion
str, ok := anything.(string)
if ok { fmt.Println(str) }
// Type switch
switch v := anything.(type) {
case int: fmt.Println("int:", v)
case string: fmt.Println("string:", v)
default: fmt.Printf("unknown: %T
", v)
}
6. ما هي التأجيل والذعر والتعافي؟
// defer: runs at function exit (LIFO order)
func readFile(path string) ([]byte, error) {
f, err := os.Open(path)
if err != nil { return nil, err }
defer f.Close() // always closes, even on error/panic
return io.ReadAll(f)
}
// panic: unrecoverable error (like exception)
// recover: catch panic in deferred function
func safeDiv(a, b int) (result int, err error) {
defer func() {
if r := recover(); r != nil {
err = fmt.Errorf("recovered from panic: %v", r)
}
}()
return a / b, nil // panics if b == 0
}
result, err := safeDiv(10, 0)
// err = "recovered from panic: runtime error: integer divide by zero"
// Rule: use panic only for truly unrecoverable errors
// Use errors for expected error cases
7. كيف يتعامل Go مع الأخطاء؟
// Go errors are values, not exceptions
func divide(a, b float64) (float64, error) {
if b == 0 {
return 0, fmt.Errorf("cannot divide by zero")
}
return a / b, nil
}
// Always check errors
result, err := divide(10, 0)
if err != nil {
log.Printf("error: %v", err)
return err
}
// Custom errors
type ValidationError struct {
Field string
Message string
}
func (e *ValidationError) Error() string {
return fmt.Sprintf("validation error on %s: %s", e.Field, e.Message)
}
// Error wrapping (Go 1.13+)
if err != nil {
return fmt.Errorf("processing user %d: %w", userID, err) // %w wraps
}
// Unwrap
var valErr *ValidationError
if errors.As(err, &valErr) {
fmt.Println("Field:", valErr.Field)
}
النجاح في المقابلة: افهم goroutines والقنوات بعمق (الفرق الأساسي عن اللغات الأخرى)، واعرف متى تستخدم القنوات المخزنة مقابل القنوات غير المخزنة، واشرح رضا الواجهة ضمنيًا، وأظهر معالجة نظيفة للأخطاء مع التغليف. تختبر أدوار Go العليا أيضًا أنماط التزامن، وملفات تعريف الأداء باستخدام pprof، ونشر الإنتاج.
🔗 Share this article
✍️ Leave a Comment