Ответ
Захват переменной (variable capture) — это механизм, при котором анонимная функция (замыкание) получает доступ к переменным из внешней, окружающей её области видимости. Замыкание «захватывает» не значение, а саму переменную, поэтому изменения переменной после создания замыкания будут видны внутри него.
func main() {
a := 1
// Замыкание захватывает переменную 'a'
f := func() {
fmt.Println(a)
}
a = 2 // Изменяем 'a' после создания, но до вызова функции
f() // Выведет 2, так как функция читает актуальное значение 'a'
}
Частая ошибка: захват переменной в цикле
Это классическая проблема при использовании горутин в циклах. Все горутины захватывают одну и ту же переменную, и к моменту их выполнения цикл, скорее всего, уже завершится, и переменная будет иметь последнее значение.
Неправильно:
for i := 0; i < 3; i++ {
// Все горутины захватывают одну и ту же переменную 'i'.
// Скорее всего, все они выведут 3.
go func() {
fmt.Println(i)
}()
}
time.Sleep(time.Second) // Ждем выполнения горутин
// Возможный вывод: 3, 3, 3
Правильно (передача значения как аргумента):
Чтобы исправить это, нужно передать значение итерационной переменной в анонимную функцию как аргумент. В этом случае для каждой горутины создается своя копия значения.
for i := 0; i < 3; i++ {
// Передаем 'i' как аргумент. 'val' - это локальная копия для каждой горутины.
go func(val int) {
fmt.Println(val)
}(i)
}
time.Sleep(time.Second)
// Вывод (в произвольном порядке): 0, 1, 2