Какие значения для анонимной функции получатся при объявлении Defer внутри цикла

Ответ

При использовании defer внутри цикла, анонимная функция (замыкание) захватывает переменные из окружающей области видимости по ссылке, а не по значению. Это значит, что к моменту выполнения defer (после завершения функции, содержащей цикл), будет использовано последнее значение переменной цикла.

Пример, демонстрирующий проблему:

package main

import (
    "fmt"
)

func main() {
    fmt.Println("Пример с проблемой:")
    for i := 0; i < 3; i++ {
        defer func() {
            fmt.Println(i) // Всегда выведет 3 (последнее значение i после завершения цикла)
        }()
    }
    fmt.Println("Конец цикла с defer")
}
// Вывод:
// Конец цикла с defer
// 3
// 3
// 3

Решение: Чтобы зафиксировать значение переменной для каждого вызова defer, передайте переменную как аргумент анонимной функции. Это создаст копию значения для каждого замыкания.

package main

import (
    "fmt"
)

func main() {
    fmt.Println("Пример с решением:")
    for i := 0; i < 3; i++ {
        defer func(val int) {
            fmt.Println(val) // Выведет 2, 1, 0 (в обратном порядке, как и положено для defer)
        }(i) // Передаем текущее значение i как аргумент
    }
    fmt.Println("Конец цикла с defer")
}
// Вывод:
// Конец цикла с defer
// 2
// 1
// 0