C ++ имеет целый набор неудобных вещей для управления:
- какие переменные захватываются
- каков их время жизни
- независимо от того, захвачены ли они значение или по ссылке
и так далее. Они содержат огромное количество сложных правил, которым вы, как программист, должны подчиняться; в противном случае поведение вашего кода не определено. В результате получается удивительно нечеткий код, который может поддерживать только опытный программист на C ++, и безопасность работы на всю жизнь. 1
Go лишены всей этой сложности. Программист вынужден писать ясный и простой код: код, который не сбивает читателя с толку. Время жизни переменной автоматически вычисляется компилятором и средой выполнения.
Что ж, к счастью для нас, программистов, - это один бит сложности. L oop в форме:
for i, item := range someslice {
go func() {
operateOn(i, &item)
}()
}
имеет только одну единственную (общую) переменную с именем item
, так что каждая из порожденных горутин работает с тем же элементом. , значение которого перезаписывается при каждой поездке через l oop. Это означает, что вы должны написать несколько менее четкое:
for i, item := range someslice {
item := item
go func() {
operateOn(i, &item)
}()
}
(обратите внимание, что i
не является проблемой, потому что его значение является просто его значением, а не указателем; я снова использую это ниже) или:
for i, item := range someslice {
go func(x T) {
operateOn(i, &x)
}(item)
}
, чтобы правильно зафиксировать элемент в локальной переменной внутри замыкания.
1 Если это не было очевидно, я действительно счастлив что код Go такой простой и понятный. Я, по крайней мере, немного саркастичен c по поводу аспекта программирования на C ++, обеспечивающего безопасность работы на всю жизнь. Неприятный материал делает позволяет C ++ эффективно использовать память и во многих случаях не требует времени выполнения G C, но это просто кошмар. Вот почему, например, в Rust существует модель собственности, но к Rust нужно некоторое время, чтобы привыкнуть.