Szukaj…


Podstawy zamknięcia

Zamknięcie to funkcja rozpatrywana łącznie z otoczeniem. Ta funkcja jest zazwyczaj funkcją anonimową zdefiniowaną w innej funkcji. Środowisko to zakres leksykalny funkcji zamykającej (bardzo podstawową ideą zakresu leksykalnego funkcji byłby zakres istniejący między nawiasami klamrowymi funkcji).

func g() {
    i := 0
    f := func() { // anonymous function
        fmt.Println("f called")
    }
}

W treści funkcji anonimowej (powiedzmy f ) zdefiniowanej w innej funkcji (powiedzmy g ) dostępne są zmienne obecne w zakresach zarówno f jak i g . Jednak to zakres g tworzy część środowiskową zamknięcia (część funkcyjna to f ), w wyniku czego zmiany dokonane w zmiennych w zakresie g zachowują swoje wartości (tzn. Środowisko utrzymuje się między wywołaniami f ) .

Rozważ poniższą funkcję:

func NaturalNumbers() func() int {
    i := 0
    f:= func() int { // f is the function part of closure
        i++
        return i
    }
    return f
}

W powyższej definicji NaturalNumbers ma wewnętrzną funkcji f które NaturalNumbers powraca. Wewnątrz f zmienna i zdefiniowana w zakresie NaturalNumbers .

Otrzymujemy nową funkcję od NaturalNumbers taką jak:

n := NaturalNumbers()

Teraz n jest zamknięciem. Jest to funkcja (zdefiniowana przez f ), która ma również powiązane środowisko (zakres NaturalNumbers ).

W przypadku n część środowiska zawiera tylko jedną zmienną: i

Ponieważ n jest funkcją, można ją wywołać:

fmt.Println(n()) // 1
fmt.Println(n()) // 2
fmt.Println(n()) // 3

Jak widać z powyższej wartości wyjściowej, za każdym razem, gdy wywoływane jest n , inkrementuje i . i zaczyna się od 0, a każde wywołanie n wykonuje i++ .

Wartość i jest zachowywana między połączeniami. Oznacza to, że środowisko, będące częścią zamknięcia, trwa.

NaturalNumbers wywołanie NaturalNumbers stworzy i zwróci nową funkcję. To zainicjuje nowe i w NaturalNumbers . Co oznacza, że nowo zwrócona funkcja stanowi kolejne zamknięcie mające tę samą część dla funkcji (wciąż f ), ale zupełnie nowe środowisko (nowo zainicjowane i ).

o := NaturalNumbers()

fmt.Println(n()) // 4
fmt.Println(o()) // 1
fmt.Println(o()) // 2
fmt.Println(n()) // 5

Zarówno n i o są zamknięcia zawierające tę samą funkcję części (co daje im takie samo zachowanie), ale różnych środowiskach. Zatem użycie zamknięć pozwala funkcjom na dostęp do trwałego środowiska, które może być użyte do przechowywania informacji między rozmowami.

Inny przykład:

func multiples(i int) func() int {
    var x int = 0
    return func() int {
        x++
        // paramenter to multiples (here it is i) also forms
        // a part of the environment, and is retained
        return x * i
    }
}

two := multiples(2)
fmt.Println(two(), two(), two()) // 2 4 6

fortyTwo := multiples(42)
fmt.Println(fortyTwo(), fortyTwo(), fortyTwo()) // 42 84 126


Modified text is an extract of the original Stack Overflow Documentation
Licencjonowany na podstawie CC BY-SA 3.0
Nie związany z Stack Overflow