Почему нам нужно скопировать значение U здесь? - PullRequest
0 голосов
/ 19 апреля 2020

Я новичок в Go и следую онлайн-курсу, где этот бит кода использовался в качестве примера:


func ConcurrentMutex(url string, fetcher Fetcher, f *fetchState) {
    var done sync.WaitGroup

    for _, u := range urls {
        done.Add(1)
        u2 := u
        go func() {
            defer done.Done()
            ConcurrentMutex(u2, fetcher, f)
        }()
        //go func(u string) {
        //  defer done.Done()
        //  ConcurrentMutex(u, fetcher, f)
        //}(u)
    }

    done.Wait()
    return
}



Тип u - это строка, и, как я вижу, это, мы должны быть в состоянии передать u к вызову ConcurrentMutex во внутренней функции без необходимости копировать его значение в u2. Тем не менее, профессор утверждал, что модель памяти Go означала, что, поскольку мы постоянно меняем значение u, оно может влиять на различные вызовы ConcurrentMutex.

Я до сих пор не совсем уверен, почему. Разве значение u в точке, где вызывается функция, не должно быть передано функции? Я бы понял, если бы мы передавали указатель, но так как это не так, это сбивает меня с толку.

Может кто-нибудь объяснить, как модель памяти Go интерпретирует этот блок?

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

1 Ответ

2 голосов
/ 19 апреля 2020

То, что вы используете, это закрытие. u2 распределяется между внутренней функцией и функцией, окружающей ее. Это означает, что при каждой итерации, когда u2 изменяется, измененное значение - это то, что видно внутренней функции. Лучший способ написания - использовать закомментированный код. Явно передав значение в подпрограмму go, вы гарантируете, что подпрограмма go несет свою собственную копию, которая не будет изменена окружающей функцией.

Что спецификация go говорит об этом: Go спецификация

Литералы функций Литерал функций представляет анонимную функцию.

FunctionLit = "fun c" Подпись FunctionBody. fun c (a, b int, z float64) bool {return a * b

f: = fun c (x, y int) int {return x + y} fun c (ch chan int) {ch <- ACK} (replyChan) Литералы функций являются замыканиями: они могут ссылаться на переменные, определенные в окружающей функции. Затем эти переменные распределяются между окружающей функцией и литералом функции, и они сохраняются до тех пор, пока они доступны. </p>

Надеюсь, это ответит на ваш вопрос.

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