Проверяет понимание итерации по строке в Go и поведения слайсов при изменении во время range.
Когда вы используете range для строки, Go автоматически декодирует UTF-8 и возвращает индекс (в байтах) и руну (символ). Это важно, потому что строка в Go — это последовательность байтов, и один символ может занимать несколько байтов. Например, кириллические буквы занимают 2 байта, а эмодзи — 4.
s := "Привет"
for i, r := range s {
fmt.Printf("%d: %c\n", i, r)
}
// Вывод: 0: П, 2: р, 4: и, 6: в, 8: е, 10: тИндекс i — это позиция начала руны в байтах, а не порядковый номер символа. Если вам нужен порядковый номер, используйте отдельный счетчик.
Когда вы итерируете по слайсу с range, Go создает копию заголовка слайса (длина, емкость, указатель на массив) в начале итерации. Это означает, что изменения, которые вы делаете внутри цикла, не влияют на количество итераций, потому что длина фиксируется заранее. Однако если вы изменяете элементы слайса, эти изменения будут видны, так как копия указывает на тот же массив.
nums := []int{1, 2, 3}
for i, v := range nums {
if i == 0 {
nums = append(nums, 4) // длина не изменится для range
}
fmt.Println(i, v)
}
// Вывод: 0 1, 1 2, 2 3 (4 не появится)Если вы изменяете элемент по индексу, это повлияет на исходный слайс, но не на текущую итерацию, так как v — это копия значения.
range, если это не предусмотрено логикой — это может привести к неожиданным результатам.range возвращает руны, а не байты, что удобно для обработки Unicode.Вывод: Понимание семантики range в Go критично для написания корректного кода при работе со строками и слайсами. Используйте range для безопасной итерации по рунам, но будьте осторожны с модификацией коллекций внутри цикла.