Почему анонимная функция работает только с последним значением переменной?

При работе с анонимными функциями в Go возникает так называемый "эффект захвата переменной" или "захват by value". Это означает, что анонимная функция не захватывает саму переменную, а копирует ее значение на момент создания функции.

Давайте рассмотрим пример:

package main

import "fmt"

func main() {
    numbers := []int{1, 2, 3, 4, 5}
    funcs := make([]func(), 0)

    for _, num := range numbers {
        funcs = append(funcs, func() {
            fmt.Println(num)
        })
    }

    for _, f := range funcs {
        f()
    }
}

В данном примере у нас есть срез чисел numbers и срез функций funcs. Мы итерируемся по числам, и для каждого числа добавляем в срез функцию, которая просто выводит это число.

Однако, если мы запустим этот код, то увидим, что в выводе будет только число 5, повторяющееся пять раз. Это происходит потому, что анонимная функция, добавляемая в funcs, захватывает переменную num по значению, а не по ссылке.

Когда мы вызываем эти анонимные функции во втором цикле, они уже имеют доступ только к одной и той же копии переменной num, которая остается равной последнему значению из итерации цикла.

Один из способов решить эту проблему - это использовать временную переменную внутри цикла, которая будет скопирована в каждую анонимную функцию:

package main

import "fmt"

func main() {
    numbers := []int{1, 2, 3, 4, 5}
    funcs := make([]func(), 0)

    for _, num := range numbers {
        numCopy := num
        funcs = append(funcs, func() {
            fmt.Println(numCopy)
        })
    }

    for _, f := range funcs {
        f()
    }
}

Теперь, когда мы вызываем каждую из функций во втором цикле, каждая из них будет использовать свою собственную копию переменной numCopy, и результатом будет вывод всех чисел из среза numbers.

В заключение, анонимные функции в Go захватывают переменные по значению, что может привести к неожиданным результатам, особенно в случаях, когда используются в циклах. Чтобы избежать этой проблемы, можно использовать временную переменную внутри цикла, чтобы гарантировать правильное захватывание значения.