for i := 0; i < 12; i++ {
i := i
...
Crazy, wygląda, to jest coś, co zobaczysz w kodzie Go. Wynika to ze sposobu działania zamknięć i sposobu, w jaki zmienne mają zasięg. Twoja anonimowa funkcja to zamknięcie przechwytujące i. W szczególności przechwytuje zmienną o nazwie i, a nie aktualną wartość i, i przechwytuje to, co ja w zakresie. W twoim oryginalnym kodzie jest to zmienna pętli, która jest tą samą zmienną dla każdej iteracji pętli. Wszystkie twoje zamknięcia przechwyciły tę samą zmienną. Dodanie i := i
deklaruje nową zmienną w każdej iteracji. Teraz każde zamknięcie przechwyci tę nową zmienną, a przy każdej iteracji będzie to inna zmienna.
W nieco bardziej szczegółowym zakresie zmienna pętli i jest instrukcją for. Obejmuje to blok pętli, ale ponieważ deklaracja zmiennej pętli i znajduje się poza blokiem, deklarowanie nowej zmiennej o tej samej nazwie wewnątrz bloku jest legalne i tworzy nową zmienną w tym punkcie bloku. Zmienna pętli jest następnie zacieniona. Często deklarowana taka zmienna idzie na stos, ale w tym przypadku analiza ucieczki kompilatora pokazuje, że twoje zamknięcie wciąż odnosi się do tej zmiennej blokowej, gdy wykracza ona poza zakres na końcu bloku, a więc zmienna jest umieszczona na sterta. Przy każdej iteracji blok jest ponownie wprowadzany i nowa zmienna i jest umieszczana na stercie.
Otrzymałem również odpowiedzi w [Najczęściej zadawanych pytaniach] (http://golang.org/doc/go_faq.html#closures_and_goroutines). – kostix