Strings: UTF-8, bytes и runes
Зачем это на интервью
В Go строка — неизменяемая последовательность байтов, обычно UTF-8. Ошибка «символ равен байту» ломает валидацию, обрезку и отображение пользовательского текста.
Минимум для E4
- Различать
len(s)в байтах и число rune. - Обходить Unicode-текст через
rangeили[]runeпри необходимости индексации по code point. - Не менять строку по индексу; строить новый результат.
Углубление для E5/Senior
rune — alias int32 и представляет Unicode code point, но не пользовательский «символ»: один grapheme cluster может состоять из нескольких rune (например, буква с combining mark или emoji ZWJ). range декодирует UTF-8 и заменяет некорректную последовательность на U+FFFD; если важна байтовая валидность, используйте utf8.ValidString. Преобразование []rune(s) выделяет память и не должно быть скрытой оптимизацией.
Ключевые понятия
s := "Go🙂"
fmt.Println(len(s)) // байты: 6
fmt.Println(utf8.RuneCountInString(s)) // code points: 3
for byteOffset, r := range s {
fmt.Printf("%d: %U\n", byteOffset, r)
}
b := []byte(s) // копия байтов; подходит для протокола/UTF-8
r := []rune(s) // декодированные code points
r[0] = 'g'
changed := string(r)s[i] возвращает byte, не «i-й Unicode-символ». Slice строки s[a:b] использует байтовые смещения и должен резать по границе UTF-8, если результат будет текстом.
Типовые вопросы
- Почему
len("é")может быть не 1?lenсчитает байты UTF-8; один code point занимает переменное число байтов.
- Что возвращает
s[i]?- Один байт типа
uint8.
- Один байт типа
- Всегда ли
rangeдаёт количество видимых символов?- Нет, он даёт rune/code point, а grapheme cluster может состоять из нескольких rune.
- Можно ли менять строку?
- Нет, строки immutable; создайте новую через builder, bytes или runes.
- Как проверить корректность UTF-8?
utf8.ValidString; не полагайтесь на успешныйrange.
Практика
- Напишите функцию, возвращающую первые
nrune без разрыва UTF-8. Готово: тесты включают ASCII, кириллицу, emoji иn=0; контракт явно говорит, что grapheme clusters не считаются. - Провалидируйте вход в UTF-8. Готово: некорректная байтовая последовательность возвращает ошибку до обработки.
Частые ошибки и ловушки
- Обрезать UI-текст по байтовому индексу.
- Путать
byte, rune и grapheme cluster. - Считать строку всегда валидным UTF-8: она может содержать произвольные байты.
Связанные темы
Коллекции и работа с данными · Builders и buffers