Поиск…


Основы закрытия

Закрытие - это функция, взятая вместе с окружающей средой. Функция обычно представляет собой анонимную функцию, определенную внутри другой функции. Окружающая среда является лексической областью охватывающей функции (самой основной идеей лексического охвата функции будет область, которая существует между фигурными скобками функции).

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

Внутри тела анонимной функции (скажем, f ), определенной в рамках другой функции (например, g ), доступны переменные, присутствующие в областях как f и g . Тем не менее, область g которая формирует часть среды, закрывает (функция является f ), и в результате изменения, внесенные в переменные в области g , сохраняют свои значения (т. Е. Среда сохраняется между вызовами f ) ,

Рассмотрим следующую функцию:

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

В приведенном выше определении NaturalNumbers имеет внутреннюю функцию f возвращаемую NaturalNumbers . Внутри f осуществляется доступ к переменной i определенной в пределах области NaturalNumbers .

Мы получаем новую функцию из NaturalNumbers следующим образом:

n := NaturalNumbers()

Теперь n является замыканием. Это функция (определенная f ), которая также имеет связанную среду (область действия NaturalNumbers ).

В случае n часть среды содержит только одну переменную: i

Так как n - функция, ее можно назвать:

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

Как видно из вышеприведенного вывода, каждый раз, когда n вызывается, он увеличивает i . i начинается с 0, и каждый вызов n выполняет i++ .

Значение i сохраняется между вызовами. То есть, окружающая среда, являющаяся частью закрытия, сохраняется.

Вызов NaturalNumbers снова создаст и вернет новую функцию. Это приведет к инициализации нового i в NaturalNumbers . Это означает, что вновь возвращенная функция образует другое закрытие, имеющее ту же часть функции (еще f ), но совершенно новую среду (вновь инициализированную i ).

o := NaturalNumbers()

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

Оба n и o - замыкания, содержащие одну и ту же функциональную часть (что дает им одно и то же поведение), но в разных средах. Таким образом, использование закрытий позволяет функциям иметь доступ к постоянной среде, которая может использоваться для сохранения информации между вызовами.

Другой пример:

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
Лицензировано согласно CC BY-SA 3.0
Не связан с Stack Overflow