AzLearn

الأساليب

Methods

مفهوم ~18 دقيقة

الأساليب — Methods

في Go لا توجد كلاسات (Classes) كما في Java أو Python، لكن هناك بديل أنيق وقوي: الأساليب (Methods). الأسلوب هو ببساطة دالة مرتبطة بنوع معين. هذا يعني أنك تستطيع إضافة سلوك لأي نوع تُعرّفه — سواء كان struct أو حتى نوع بسيط مثل int.

تعريف أسلوب بسيط

الفرق بين الدالة العادية والأسلوب هو وجود مُستقبِل (Receiver) بين كلمة func واسم الدالة:

// دالة عادية — Regular function
func Area(width, height float64) float64 { ... }

// أسلوب على نوع — Method on a type
func (r Rectangle) Area() float64 { ... }

المُستقبِل (r Rectangle) يربط هذا الأسلوب بالنوع Rectangle. الآن يمكنك استدعاؤه عبر rect.Area().

مثال عملي

main.go

مستقبل القيمة vs مستقبل المؤشر — Value vs Pointer Receiver

هذا من أهم المفاهيم التي يجب أن تفهمها جيداً. عندما تُعرّف أسلوباً، المُستقبِل يمكن أن يكون:

  1. مستقبل قيمة (r Rectangle) — يعمل على نسخة من القيمة
  2. مستقبل مؤشر (r *Rectangle) — يعمل على القيمة الأصلية نفسها

القاعدة الذهبية:

  • إذا الأسلوب يُعدّل الكائن ← استخدم مستقبل مؤشر *T
  • إذا الأسلوب يقرأ فقط ← مستقبل قيمة T يكفي
  • إذا الـ struct كبير ← مستقبل مؤشر أفضل (تجنب النسخ)
  • في الممارسة: إذا أسلوب واحد يحتاج مؤشر، اجعل كل أساليب النوع بمؤشر للاتساق
main.go

الفرق العملي بين النوعين

لنرى ماذا يحدث عندما نستخدم مستقبل قيمة مع أسلوب يحاول التعديل:

main.go

أساليب على أنواع غير Struct

يمكنك تعريف أساليب على أي نوع تُعرّفه — ليس فقط struct:

main.go

مجموعة الأساليب — Method Sets

هذا مفهوم مهم لفهم الواجهات لاحقاً:

  • القيمة من نوع T تستطيع استدعاء أساليب T فقط (مستقبل قيمة)
  • المؤشر من نوع *T يستطيع استدعاء أساليب T و *T (كلا النوعين)

عملياً Go يقوم بتحويل تلقائي في معظم الحالات، لكن هذا يُهم عند التعامل مع الواجهات.

أخطاء شائعة

خطأ 1: نسيان أن مستقبل القيمة يعمل على نسخة

// ❌ خطأ شائع — هذا لا يُعدّل الأصل
func (u User) UpdateName(name string) {
    u.Name = name  // تعديل على نسخة!
}

// ✅ الصحيح
func (u *User) UpdateName(name string) {
    u.Name = name  // تعديل على الأصل
}

خطأ 2: محاولة تعريف أسلوب على نوع من حزمة أخرى

// ❌ لا يمكنك تعريف أسلوب على int مباشرة
func (n int) Double() int { return n * 2 }

// ✅ عرّف نوعك الخاص
type MyInt int
func (n MyInt) Double() int { return int(n) * 2 }
تحدي — Challenge