Короче говоря, предупреждение означает, что вы берете адрес переменной цикла.
Это происходит потому, что в for
операторах повторно используются переменные итерации. На каждой итерации значение следующего элемента в выражении диапазона присваивается переменной итерации; v
не меняется, меняется только его значение. Следовательно, выражение &v
относится к одному и тому же месту в памяти.
Следующий код печатает один и тот же адрес памяти четыре раза:
for _, n := range []int{1, 2, 3, 4} {
fmt.Printf("%p\n", &n)
}
Когда вы сохраняете адрес переменной итерации или используете ее в замыкании внутри цикла, к моменту разыменования указателя его значение может измениться. Инструменты статического анализа обнаружат это и выдадут предупреждение, которое вы увидите.
Распространенные способы предотвращения проблемы:
- проиндексировать ранжированный срез/массив/карту. Это берет адрес фактического элемента в i-й позиции вместо переменной итерации
for i := range versions {
res := createWorkerFor(&versions[i])
}
- переназначить переменную итерации внутри цикла
for _, v := range versions {
v := v
res := createWorkerFor(&v) // this is now the address of the inner v
}
- с замыканиями, передайте переменную итерации в качестве аргумента замыканию
for _, v := range versions {
go func(arg ObjectDescription) {
x := &arg // safe
}(v)
}
person
blackgreen
schedule
04.07.2021
v
в цикле опасно (в зависимости от того, что вы с ним делаете, но его сохранение и асинхронное использование сломают ситуацию). См. эту запись распространенные ошибки. - person Marc   schedule 18.06.2020for
используется только одна переменнаяv
, а значениеv
обновляется циклом for. Но так как это всего лишь одна переменная, то у нее всего один адрес:&v
является константой и не изменяется во время итерации цикла. Это типичная проблема в параллельном коде, так как все созданные рабочие процессы будут работать с одним и тем же местом в памяти и, следовательно, либо с одним и тем же значением, либо со значением, которое является колоритным. См. golang.org/doc/faq#closures_and_goroutines. - person Volker   schedule 18.06.2020&
, что может выделить немного больше памяти, но объект, который я передал, был в основном небольшой частью запроса БД (данные сервера, такие как имя хоста, IP, ОС). и т. д.) ... поэтому, удалив амперсанд, я передал копию методу, обрабатывающему данные, вместо ссылки. - person TommyTheKid   schedule 18.03.2021