При семантике циклов Go 1.22+ вывод — 10 20. При старой семантике общей переменной v оба указателя после цикла дают 40.
Неожиданное поведение указателей, получаемых в range, при их добавлении в срез
При семантике циклов Go 1.22+ вывод — 10 20. При старой семантике общей переменной v оба указателя после цикла дают 40.
Короткий ответ
Что ответить на собеседовании
Подробный разбор
Ответ с пояснениями
Условие
Определите, какие числа будут напечатаны программой, и поясните причину странного результата, возникающего при итерации по массиву с помощью цикла range и сохранении полученных указателей в срез.
package main
import "fmt"
func main() {
first := []int{10, 20, 30, 40}
second := make([]*int, len(first))
for i, v := range first {
second[i] = &v
}
fmt.Println(*second[0], *second[1])
}
Ответ
При семантике циклов Go 1.22+ вывод — 10 20. При старой семантике общей переменной v оба указателя после цикла дают 40.
В новом режиме объявленная через := переменная v создаётся заново на каждой итерации. При старом режиме одна переменная переиспользуется, поэтому все сохранённые адреса совпадают.
Версия семантики зависит в том числе от версии Go, заданной модулем, а не только установленного компилятора. Если нужны указатели именно на элементы first, пишите second[i] = &first[i]: это не адрес копии v и не зависит от изменения семантики циклов. Изменения через такие указатели будут затрагивать исходный срез.