الانتقال إلى المحتوى الرئيسي
الوحدة 3 · الدرس 4 من 514/50 في الدورة~12 min
دروس الوحدة (4/5)

عمليات الإغلاق والوظائف كقيم

في Go، الوظائف هي قيم من الدرجة الأولى: يمكن إسنادها إليها المتغيرات، وتمريرها إلى وظائف أخرى، وإعادتها. الإغلاق هو وظيفة حرفية (مجهولة) ** تلتقط ** متغيرات ملف البيئة التي يتم تعريفها.

دالة حرفية

دالة بدون اسم، مكتوبة في السطر. اتصل به على الفور أو تعيينه:

Go
greet := func(name string) {
    fmt.Println("ciao", name)
}
greet("Anna")

// invocata immediatamente:
func() { fmt.Println("subito") }()

نوع greet هو func(string).

الاستيلاء على البيئة: الإغلاق

يمكن للوظيفة الحرفية قراءة وتعديل المتغيرات المرئية فيها نطاقه المعجمي، حتى بعد عودة الوظيفة الخارجية:

Go
func counter() func() int {
    n := 0
    return func() int {
        n++
        return n
    }
}

c := counter()
fmt.Println(c(), c(), c())  // 1 2 3

n "يعيش" طالما أن إغلاقًا واحدًا على الأقل يشير إليه. كل دعوة ل يقوم counter() بإنشاء n جديد ومستقل.

الإغلاق كرد اتصال

نمط شائع جدًا:

Go
nums := []int{3, 1, 2}
sort.Slice(nums, func(i, j int) bool {
    return nums[i] < nums[j]
})

يلتقط الإغلاق nums ويحدد الترتيب.

وظائف كمعلمات

لقبول دالة كمعلمة، اكتب نوعها:

Go
func apply(nums []int, f func(int) int) []int {
    out := make([]int, len(nums))
    for i, n := range nums {
        out[i] = f(n)
    }
    return out
}

double := func(x int) int { return x * 2 }
apply([]int{1, 2, 3}, double)   // [2 4 6]

إذا أصبح من الصعب قراءة التوقيع، فحدد اسم مستعار للنوع:

Go
type Transform func(int) int
func apply(nums []int, f Transform) []int { ... }

جربه

تمرين#go.m3.l4.e1
المحاولات: 0جارٍ التحميل…

تحديد العداد () الذي يُرجع الإغلاق: كل استدعاء للإغلاق يزيد ويعيد عدادًا داخليًا.

جارٍ تحميل المحرر…
إظهار التلميح

يجب الإعلان عن `n` قبل الإرجاع؛ الإغلاق يلتقطها.

الحل متاح بعد 3 من المحاولات

تمرين#go.m3.l4.e2
المحاولات: 0جارٍ التحميل…

قم بتعيين دالة حرفية إلى f تطبع "ciao"، ثم اتصل بها.

جارٍ تحميل المحرر…
إظهار التلميح

بناء الجملة: `f := func() { ... }` ثم `f()`.

الحل متاح بعد 3 من المحاولات

Quiz#go.m3.l4.e3
جاهز

ماذا يطبع هذا؟ (احترس من نطاق الإغلاق)

Go
mk := func() func() int {
    x := 0
    return func() int { x++; return x }
}
a := mk()
b := mk()
fmt.Println(a(), a(), b())
خيارات الإجابة

خلاصة

  • الوظائف من الدرجة الأولى: قابلة للإحالة، ومقبولة، وقابلة للإرجاع.
  • الوظيفة الحرفية: func(params) ret { ... }، مجهول.
  • الإغلاق: يلتقط متغيرات النطاق المعجمي، ويبقيها حية.
  • نوع الوظيفة الصريحة في المعلمات: func(int) int.
  • منذ Go 1.22، كل تكرار له نسخته الخاصة من متغير الحلقة.