Ответ вслух Middle Строки, байты и руны обновлено

Строки и UTF-8 в Go

Вопрос

Объясните, как в Go устроены строки, байты и руны. Как правильно работать с текстом на русском?

Попробуйте сами

Ответьте вслух за 2 минуты, как на собесе. Потом сверьтесь с тезисами: что прозвучало, а что нет.

Показать ответ и разбор

Коротко

Строка в Go это неизменяемый набор байтов с длиной. Исходники Go в UTF-8, поэтому литералы тоже в UTF-8, но язык не запрещает класть туда любые байты. len(s) считает байты: у «привет» их 12.

Что должно прозвучать в ответе

  • Строка это неизменяемая последовательность байтов, обычно UTF-8

  • `len` даёт байты, `utf8.RuneCountInString` символы

  • byte это uint8, rune это int32 кодовая точка

  • `range` по строке декодирует руны, индексы байтовые

  • Для посимвольных операций `[]rune`, для склейки `strings.Builder`

  • Конвертации `[]byte(s)` и `string(b)` обычно копируют

Что могут спросить следом

  • Как обрезать строку до 10 символов, не сломав UTF-8?
  • Почему длина эмодзи может быть больше одной руны?

Разбор

Строка в Go это неизменяемый набор байтов с длиной. Исходники Go в UTF-8, поэтому литералы тоже в UTF-8, но язык не запрещает класть туда любые байты. len(s) считает байты: у «привет» их 12. Отдельный символ это руна, то есть int32 с кодовой точкой Unicode, а byte это uint8. Индекс s[i] даёт байт, поэтому для кириллицы им пользоваться нельзя. range по строке декодирует UTF-8 и выдаёт байтовый индекс и руну. Для посимвольных операций, например обрезки до N символов или разворота, перевожу в []rune, или иду range и отсчитываю руны, чтобы резать по байтовому индексу без лишней аллокации. Для склейки использую strings.Builder. Помню, что []byte(s) копирует, и в горячем коде стараюсь работать с одним представлением. И что «символ» для человека иногда состоит из нескольких рун: эмодзи с цветом кожи или флаги.

Ответьте сами, а не прочитайте

В тренажёре вопрос попадёт в повторения и вернётся, когда начнёт забываться. Плюс билеты с зачётом: 20 вопросов, не больше 2 ошибок.