Отображение массива в массив функций - PullRequest
0 голосов
/ 12 января 2020
package main

import (
    "fmt"
)

func main() {
    a := []int{1, 2, 3}
    var fs []func()
    for idx, x := range a {
        f := func() {
            fmt.Println(idx, " ", x)
        }
        fs = append(fs, f)

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

У меня есть этот кусок кода. Вывод этого кода:

2 3
2 3
2 3

Что не соответствует моим ожиданиям

0 1
1 2
2 3

Как я понимаю, что после l oop, ссылка idx и x будет указывать на последний элемент массива a, после чего функция будет выполняться для l oop, поэтому она выведет 2 3 для fs[i].

Ответы [ 2 ]

2 голосов
/ 12 января 2020

Функции относятся к отдельным idx и x переменным. Переменные изменяются на каждом шаге через l oop и имеют значения 2 и 3 при выходе из l oop.

Исправлено путем объявления переменных для каждой функции:

for idx, x := range a {
    idx := idx // <-- add this line and next
    x := x
    f := func() {
        fmt.Println(idx, " ", x)
    }
    fs = append(fs, f)
}

Внутренние переменные idx и x устанавливаются один раз с ожидаемыми значениями.

Эта проблема описано в FAQ .

1 голос
/ 12 января 2020

Это связано с концепцией закрытия. В основном переменные idx и x, которые вы используете внутри функции f , используют внешние переменные. Поэтому, когда функция фактически вызывается, она все еще «ссылается» на внешние переменные, которые были повторены до конца. Есть много решений, чтобы исправить это, для вашего кода одно исправление - назначить новые переменные внутри для l oop. В приведенном ниже коде a и b берет копию для каждой итерации и использует то же самое при вызове функции.

package main

import (
    "fmt"
)

func main() {
    a := []int{1, 2, 3}
    var fs []func()
    for idx, x := range a {
        a := idx
        b := x

        f := func() {
            fmt.Println(a, " ", b)
        }
        fs = append(fs, f)

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

Этот код будет выводить

0   1
1   2
2   3

Вы можете увидеть некоторые детали в здесь .

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...