Материал проходит вычитку — возможны неточности.
Урок 10 из 118

Руна — это code point

Валидация имён сломалась во второй раз — теперь на букве «ё». Счётчик символов показал у «ё» два вместо одного, и имена клиента с умлаутами не прошли проверку. Аня переоткрыла тикет Сергея.

Главная мысль

rune (псевдоним int32) — номер символа Unicode до кодирования в байты, а range по строке перебирает именно руны, отдавая байтовый индекс каждого символа.

В прошлом уроке мы работали со строками как с последовательностью байтов. Для ASCII этого достаточно, но с кириллицей такой подход уже не работает: нужна единица «символа». В Go эта единица называется руной.

rune — псевдоним int32, точно так же как byte — псевдоним uint8. Руна хранит один Unicode code point — абстрактный номер символа до того, как его закодировали в байты. Разница между byte и rune в ширине: байт дотягивается до значения 255, а code point'ов в Unicode 1 114 112, поэтому руне нужны 32 бита.

Руна — это число

Go

Литерал 'п' — это именно code point 1087, а не его UTF-8-байты. В памяти руна лежит как обычное число, и это число можно печатать, сравнивать, класть в слайс. Два байта 0xD0 0xBF, в которые «п» превращается при кодировании, здесь не участвуют.

Range перебирает руны

Отсюда видно, почему индексация строки отдаёт байт, а range — руну: это два разных действия с разными определениями в спецификации. s[i] — «отдай i-й байт». А range по строке спецификация определяет как обход Unicode code points: на каждом шаге он читает байт, по его старшим битам определяет, сколько байт занимает символ, собирает из них число и отдаёт его как руну. Вместе с руной range отдаёт индекс — но это индекс первого байта символа, а не порядковый номер символа.

Go
0 'h'
1 'é'
3 'l'
4 'l'
5 'o'

é занимает два байта, поэтому после него индекс перепрыгивает с 1 сразу на 3. Индексы в цикле байтовые, и резать строку ими можно: s[1:3] — это как раз é. А вот использовать i как номер символа нельзя, для этого нужен отдельный счётчик.

В следующем уроке

Вы узнаете:

  • как первый байт кодирует длину символа в UTF-8
  • почему нет O(1)-доступа к i-й руне
Задание · вопросы

Проверьте себя

Вопрос 1 из 3

Что такое rune в Go?

Вопрос 2 из 3

Что перебирает range по строке?

Вопрос 3 из 3

Для s := "héllo" индексы в range идут 0, 1, 3, 4, 5. Почему пропущен 2?

Итоги

Байты — это то, как строка хранится и что отдают len и индексация; руны — то, чем оперирует range и что стоит считать символом. Обрабатывая текст, держи оба уровня в голове и проверяй, на каком из них сейчас работаешь.

Наш сайт собирает куки. Чтобы тебе было удобнее им пользоваться. Нажимая на кнопку, ты даёшь разрешение собирать куки