Ответ
В Go строка (string
) — это неизменяемая (immutable) последовательность байтов в кодировке UTF-8. Из-за этого существуют два основных способа итерации с принципиально разным поведением.
1. Итерация по рунам (символам) с помощью range
Этот способ является предпочтительным при работе с текстом. Оператор range
автоматически декодирует UTF-8 последовательности и на каждой итерации возвращает индекс начала руны в байтах и саму руну (тип rune
, который является псевдонимом для int32
).
s := "Привет"
// i - индекс начала руны в байтах
// r - сама руна (символ)
for i, r := range s {
// Привет -> П(2 байта) р(2) и(2) в(2) е(2) т(2)
fmt.Printf("Индекс байта: %d, Руна: %cn", i, r)
}
// Вывод:
// Индекс байта: 0, Руна: П
// Индекс байта: 2, Руна: р
// Индекс байта: 4, Руна: и
// ...
2. Итерация по байтам с помощью стандартного цикла for
Этот способ итерируется по каждому байту строки. Он подходит для работы с ASCII-строками или бинарными данными, представленными в виде строки, но некорректен для многобайтовых символов (кириллица, эмодзи и т.д.).
s := "Hi Привет"
for i := 0; i < len(s); i++ {
// s[i] возвращает i-й байт строки
fmt.Printf("%#x ", s[i])
}
// Вывод будет содержать байты каждого символа:
// 0x48 0x69 0x20 0xd0 0x9f 0xd1 0x80 ...
Что важно помнить:
len(s)
возвращает количество байтов, а не символов (рун).- Для получения количества символов (рун) используйте
utf8.RuneCountInString(s)
или, если нужна дальнейшая работа с рунами,len([]rune(s))
. - Прямое обращение к символу по индексу
s[i]
дает байт, а не руну, что может привести к ошибкам с не-ASCII символами.