Почему я должен передавать внешнюю переменную литеральной функции в golang

У меня есть фрагмент кода ниже

package main

import (
    "fmt"
    "net/http"
    "time"
)

func checkLink(url string, ch chan string) {
    _, err := http.Get(url)
    if err != nil {
        fmt.Println(url, "Did not respond")
        ch <- "Did not respond I think"
        return
    }

    fmt.Println(url, "responded normally!")
    ch <- url
}

func main() {
    urls := []string{
        "https://google.com",
        "https://amazon.com",
        "https://facebook.com",
        "https://golang.org",
        "https://stackoverflow.com",
    }

    c := make(chan string)

    for _, url := range urls {
        go checkLink(url, c)
    }

    for url := range c {
        go func() {
            time.Sleep(5 * time.Second)
            checkLink(url, c)
        }()
    }
}

и это выход

https://golang.org responded normally!
https://stackoverflow.com responded normally!
https://google.com responded normally!
https://facebook.com responded normally!
https://amazon.com responded normally!
https://amazon.com responded normally!
https://amazon.com responded normally!
https://amazon.com responded normally!
https://amazon.com responded normally!
https://amazon.com responded normally!
https://amazon.com responded normally!
https://amazon.com responded normally!
https://amazon.com responded normally!
https://amazon.com responded normally!
https://amazon.com responded normally!

и после поиска я обнаружил, что мне нужно передать переменную url в литеральную функцию и заставить ее принимать строковую переменную, как показано ниже.

for url := range c {
        go func(url string) {
            time.Sleep(5 * time.Second)
            checkLink(url, c)
        }(url)
    }

но я не понял почему. и почему URL-адрес amazon.com продолжал печатать так, а переменная URL не обновлялась?


person Hazem Taha    schedule 08.07.2021    source источник
comment
Поскольку url — это переменная цикла, которая повторно используется в каждой итерации, и если ваша анонимная функция (запущенная как горутина) ссылается на нее, то ее значение не останется тем, которое было присвоено ей при запуске горутины. Это также гонка данных и, как таковое, неопределенное поведение.   -  person icza    schedule 08.07.2021
comment
Пока внутренняя функция ожидает 5 секунд, цикл for продолжает изменять значение внутри url. Когда вы не передаете url в функцию, вы продолжаете ссылаться на исходную переменную, а не на исходное значение. Передавая url в качестве параметра, параметр сохраняет значение в течение 5-секундного ожидания даже при изменении переменной цикла. Это становится намного более очевидным, когда параметр внутренней функции не затеняет переменную цикла.   -  person Corey Ogburn    schedule 08.07.2021
comment
Вы можете прочитать эту полезную статью о распространенном замыкании. ошибки в работе.   -  person Benny Jobigan    schedule 08.07.2021
comment
Большое спасибо, ребята! Вы хоть представляете, почему мой вопрос получил -2?   -  person Hazem Taha    schedule 15.07.2021