0Pricing
Go Academy · درس

مستقبلات المؤشرات في الطرائق

تعديل حالة البنية عبر مستقبلات المؤشرات

مستقبلات المؤشرات في الطرائق درس مجاني في Go Academy على CoddyKit. هذا هو الدرس 3 من أصل 4. يمكنك قراءة الدرس كاملاً أدناه مجاناً — ثم تمرن عليه مباشرة في المتصفح باستخدام محرر أكواد مدمج ومدرس ذكاء اصطناعي متاح 24/7. هذا الدرس جزء من مسار التعلم في Go Academy، وتقدمك يتزامن عبر الويب وتطبيق CoddyKit. تتضمن دورة Go Academy 4 دروس في المجموع.

مراجعة: مستقبِل القيمة مقابل مستقبِل المؤشر

يعمل مستقبِل القيمة على نسخة من البنية. أما مستقبِل المؤشر فيعمل على البنية الأصلية. استخدم مستقبِلات المؤشر كلما احتاج الأسلوب إلى تعديل الحالة.

التعديل باستخدام مستقبِل المؤشر

لا يمكن تعديل البنية إلا باستخدام مستقبِل مؤشر:

package main
import "fmt"

type Stack struct{ items []int }

func (s *Stack) Push(v int) { s.items = append(s.items, v) }
func (s *Stack) Pop() int {
    n := len(s.items) - 1
    v := s.items[n]
    s.items = s.items[:n]
    return v
}

func main() {
    var st Stack
    st.Push(1); st.Push(2)
    fmt.Println(st.Pop()) // 2
}

قاعدة الاتساق

إذا احتاج أي أسلوب في نوع ما إلى مستقبِل مؤشر، فينبغي أن تستخدم جميع الأساليب مستقبِلات المؤشر. يؤدي المزج بين النوعين إلى مشكلات عند استيفاء الواجهات:

package main
import "fmt"

type Counter struct{ n int }

func (c *Counter) Inc()   { c.n++ }   // pointer
func (c *Counter) Val() int { return c.n } // pointer too

func main() {
    c := &Counter{}
    c.Inc(); c.Inc()
    fmt.Println(c.Val()) // 2
}

استيفاء الواجهة

لا يوجد أسلوب مستقبِل المؤشر إلا في مجموعة أساليب *T، وليس T. ويؤثر ذلك في استيفاء الواجهات:

package main
import "fmt"

type Writer interface{ Write([]byte) }

type File struct{ name string }
func (f *File) Write(b []byte) { fmt.Println(string(b)) }

func main() {
    var w Writer = &File{"out.txt"} // OK
    // var w Writer = File{} — compile error
    w.Write([]byte("hello"))
}

أخذ العنوان تلقائيًا

تأخذ Go العنوان تلقائيًا عند استدعاء أسلوب ذي مستقبِل مؤشر على قيمة يمكن أخذ عنوانها:

package main
import "fmt"

type Box struct{ V int }
func (b *Box) Double() { b.V *= 2 }

func main() {
    b := Box{5}
    b.Double()          // Go does (&b).Double()
    fmt.Println(b.V)    // 10
}

القيم التي لا يمكن أخذ عناوينها

لا يمكنك استدعاء أساليب ذات مستقبِلات مؤشرات على قيم لا يمكن أخذ عناوينها (عناصر الخرائط وقيم الإرجاع من الدوال التي لم تُسند إلى متغيرات):

package main

type T struct{ V int }
func (t *T) Set(v int) { t.V = v }

func getT() T { return T{} }

func main() {
    var t T
    t.Set(1)       // OK — t is addressable
    // getT().Set(1) — ERROR: cannot take address of getT()
    _ = t
}

مستقبِلات البنى الكبيرة

استخدم دائمًا مستقبِلات المؤشر مع البنى الكبيرة لتجنّب النسخ المكلف عند كل استدعاء لأسلوب:

package main

type Image struct{ pixels [1024][1024]uint8 }

// Value receiver copies 1MB per call!
func (img Image) Bad() uint8 { return img.pixels[0][0] }

// Pointer receiver — zero copy
func (img *Image) Good() uint8 { return img.pixels[0][0] }

func main() { _ = Image{} }

مستقبِلات المؤشر nil

يمكن للأساليب ذات مستقبِلات المؤشر التعامل مع nil بأمان:

package main
import "fmt"

type List struct{ head *node }
type node struct{ val int; next *node }

func (l *List) Len() int {
    if l == nil { return 0 }
    count := 0
    for n := l.head; n != nil; n = n.next { count++ }
    return count
}

func main() {
    var l *List
    fmt.Println(l.Len()) // 0
}

التضمين ومستقبِلات المؤشر

عند تضمين نوع ذي مستقبِلات مؤشرات، يجب استخدام البنية الخارجية أيضًا كمؤشر للوصول إلى الأساليب المروّجة:

package main
import "fmt"

type Base struct{ V int }
func (b *Base) Set(v int) { b.V = v }

type Derived struct{ Base }

func main() {
    d := &Derived{}
    d.Set(42)           // promoted pointer-receiver method
    fmt.Println(d.V)    // 42
}

نسخ كائنات Mutex

لا تنسخ مطلقًا بنية تحتوي على sync.Mutex — استخدم دائمًا مستقبِل مؤشر أو مرّرها بواسطة مؤشر. يؤدي نسخ كائن Mutex مقفول إلى حالة توقف تام:

package main
import "sync"

type Safe struct {
    mu sync.Mutex
    v  int
}

// Correct: pointer receiver
func (s *Safe) Set(v int) {
    s.mu.Lock()
    defer s.mu.Unlock()
    s.v = v
}

func main() { _ = Safe{} }

يكتشف go vet الأخطاء

شغّل go vet ./... لاكتشاف الأخطاء الشائعة المتعلقة بمستقبِلات المؤشر، مثل نسخ كائنات Mutex وأقفالها. وهو جزء من مسارات go build وفحوصات CI.

تحقّق سريع

ما الأنواع التي توجد في مجموعة أساليبها دالة ذات مستقبِل مؤشر؟

مراجعة

أهم النقاط:

  • تُجري مستقبِلات المؤشر تعديلات؛ أما مستقبِلات القيمة فلا تفعل ذلك
  • استخدم نوع المستقبِل نفسه في جميع الأساليب التابعة لنوع واحد
  • لا يستوفي الواجهات التي تتطلب أساليب ذات مستقبِلات مؤشرات سوى *T
  • لا تنسخ البنى التي تحتوي على كائنات Mutex — استخدم مستقبِلات المؤشر

مهمة تدريبية

نفّذ بنية Queue باستخدام الأساليب ذات مستقبِلات المؤشر Enqueue(int) وDequeue() (int, bool) وLen() int، على أن تستند إلى شريحة []int.

الأسئلة الشائعة

هل درس «مستقبلات المؤشرات في الطرائق» مجاني؟

نعم — نص درس «مستقبلات المؤشرات في الطرائق» كامل متاح مجاناً هنا على الويب. لتمرينه بشكل تفاعلي (محرر أكواد مدمج ومدرس ذكاء اصطناعي متاح 24/7) وفتح باقي دورة Go Academy، انتقل إلى CoddyKit PRO. تتضمن دورة Go Academy 4 دروس في المجموع.

ماذا ستتعلم في «مستقبلات المؤشرات في الطرائق»؟

تعديل حالة البنية عبر مستقبلات المؤشرات تتمرن على Go Academy مع أكواد عملية تشغلها مباشرة في المتصفح، ومدرس ذكاء اصطناعي متاح 24/7 يجيب على أسئلتك أثناء عملك.

هل أحتاج إلى خبرة سابقة لأبدأ Go Academy؟

لا تُشترط خبرة سابقة. Go Academy على CoddyKit منظم للمبتدئين حتى المتقدمين، لذا يمكنك البدء من هنا أو من البداية والتقدم بسرعتك الخاصة. هذا هو الدرس 3 من أصل 4.

كم من الوقت يستغرق درس «مستقبلات المؤشرات في الطرائق»؟

معظم دروس CoddyKit تستغرق حوالي 5–10 دقائق. كل منها موجز وتفاعلي، لذا تحرز تقدماً مستمراً وتستأنف من حيث توقفت عبر الويب والتطبيق.

هل يمكنني كتابة وتشغيل أكواد في درس Go Academy هذا؟

نعم. كل درس في Go Academy يتضمن محرر أكواد مدمج، لذا تكتب وتشغل أكواداً حقيقية مباشرة في متصفحك وتحصل على تعليقات فورية من الذكاء الاصطناعي — بدون إعداد محلي.

جميع الدروس في هذه الدورة

  1. ما المؤشرات؟
  2. المؤشرات والدوال
  3. مستقبلات المؤشرات في الطرائق
  4. ‏new() ومتى تستخدم المؤشرات
← العودة إلى Go Academy