Closure

В этом примере на Go демонстрируется замыкание (closure) — функция, которая запоминает окружение, в котором она была создана.

1. Функция intSeq() создаёт замыкание

func intSeq() func() int {
    i := 0              // Локальная переменная внутри intSeq
    return func() int { // Возвращаемая анонимная функция
        i++            // Замыкание "видит" переменную i
        return i
    }
}
  • i := 0 — это локальная переменная внутри intSeq.
  • Возвращаемая функция func() int “замыкается” вокруг i, то есть запоминает её и может изменять.

2. Создаём экземпляр замыкания

nextInt := intSeq() // Переменная nextInt теперь — функция
  • При вызове intSeq():
    • Создаётся переменная i = 0.
    • Возвращается функция-замыкание, которая удерживает ссылку на i.

3. Вызов nextInt() изменяет состояние i

p(nextInt()) // Выведет: === 1 ===
p(nextInt()) // Выведет: === 2 ===
p(nextInt()) // Выведет: === 3 ===
  • Каждый вызов nextInt():
    • Увеличивает i на 1 (i++).
    • Возвращает новое значение.
  • i сохраняется между вызовами — это и есть “запомненное окружение”.

4. Новое замыкание — новый экземпляр i

newInts := intSeq() // Создаётся новый экземпляр замыкания
p(newInts())        // Выведет: === 1 === (не 4!)
  • newInts — это новое замыкание с собственной переменной i = 0.
  • Оно не связано с nextInt — их состояния (i) независимы.

Итог: как работает замыкание

  1. Запоминает окружение (переменные, например i), даже после выхода из внешней функции.
  2. Сохраняет состояние между вызовами (i увеличивается).
  3. Каждое новое замыкание создаёт свой экземпляр переменных.

Это полезно для:

  • Генераторов (как в примере).
  • Callback-функций с сохранением состояния.
  • Инкапсуляции данных (аналог private переменных в ООП).

Пример в JavaScript (для сравнения):

function intSeq() {
    let i = 0;
    return () => ++i;
}

Работает аналогично!