דילוג לתוכן המרכזי
מודול 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, לכל for iteration יש עותק משלו של משתנה הלולאה.