Pull to refresh

Comments 11

Кто не ловил захват переменной в цикле , тот не писал на go

База + update. Спасибо!

Копирование элементов. Напомню, что каждый раз, когда вы выполняете обход массивов и слайсов, Go создает копию каждого элемента

Это вполне ожидаемое поведение, я не припомню языков где иначе (даже если значения массива ссылки/указатели, то по сути имеем их копию). А вот про то, что выражение range создаёт копию самого массива/слайса можно было упомянуть. В случае массива это полноценная копия, в случае слайса копия только описывающей слайс структуры. Отсюда всякие нюансы с изменением во время итерации, их полезно знать.

В этом примере удаление элементов из map во время итерации небезопасно и может привести к ошибкам во время выполнения или неожиданному поведению, поскольку сама map изменяется во время итерации.

Это откуда такая информация? Если почитать практику и спеки, везде написано, что это безопасно, ну или наоборот нигде не написано что так делать нельзя. Конкурирующий доступ запрещен да. Модификация мапы в одном потоке разрешена. Про range по мапе в спеке написано, что удаленные элементы, до которых вы еще не дошли не будут пройдены в цикле (что звучит логично), а добавленные могут а могут и не быть пройдены (т.к. порядок не гарантирован)

Добавлю ссылку на спеку https://go.dev/ref/spec#For_range
3. The iteration order over maps is not specified
and is not guaranteed to be the same from one iteration to the next.
If a map entry that has not yet been reached is removed during iteration,
the corresponding iteration value will not be produced. If a map entry is
created during iteration, that entry may be produced during the iteration or
may be skipped. The choice may vary for each entry created and from one
iteration to the next.

Зашёл написать ровно этот же комментарий ровно с этой же ссылкой.
Спасибо за бдительность.

Что делает собственно ключевое слово range? Можно ли его использовать вне цикла? Или это просто такое украшательство чтобы отличить for по индексу от for по диапазону?

range итерирует структуры, которые описаны в статье (слайс/массив, мапа, строка), вне цикла использовать его не получится - он часть синтаксиса. При этом это не "синтаксический сахар" к более длинным конструкциям: заменить его на на что-то другое можно для строк и массивов, но не для мап - т.к. отсутствуют публичные методы для получения итератора мапы.

исходники его тут кстати https://github.com/golang/go/blob/master/src/cmd/compile/internal/walk/range.go

Главная новость заключается в том, что Go 1.22 изменяет правила определения области видимости для переменных в циклах for. Раньше переменные цикла имели область видимости для всего цикла. Теперь каждая итерация получает свою собственную область видимости

Но

Копирование элементов. Напомню, что каждый раз, когда вы выполняете обход массивов и слайсов, Go создает копию каждого элемента

т.е. в цикле

for i,val = range arr {}

Переменная val это копия (на стеке) в каждой итерации и эта копия со стека удаляется в конце каждой итерации и в начале следующей создается другая копия. Т.е. область видимости копии и так ограничена одной итерацией. Или нет? В чем тогда нововведение 1.22 в части области видимости копии?

Я так понял, что переменная val существует в единственном экземляре, и на каждой итерации в неё копируется значение очередного элемента контейнера.

Интересное нововведение. Интересно как они это реализовали. Предполагаю, что создаётся новая переменная под капотом и уже она используется в другой closure. Другими словами - перехват переменной делают за программиста. А без этого все остается как было

Sign up to leave a comment.