Зачем нужны руны в Go и почему строка не подходит
Что проверяют
Понимаете ли вы, как в Go устроены строки на уровне байтов, и не сломаете ли кириллицу при обработке текста. Следом обычно просят сказать, что вернут len("привет") и s[0], и как посчитать символы.
Как отвечать
Начните с устройства типов:
string: неизменяемая последовательность байтов. Кодировку тип не хранит, но исходники Go пишутся в UTF-8, поэтому литералы и почти весь текст на практике тоже в UTF-8;byte: синонимuint8, один байт;rune: синонимint32, одна кодовая точка Unicode. Это номер символа, а не его байтовое представление.
Отсюда поведение, которое и объясняет, зачем нужны руны:
len(s): возвращает байты.len("привет")равно 12, потому что каждая кириллическая буква в UTF-8 занимает два байта;s[i]: даёт байт, а срезs[:3]может разрезать букву пополам и получить невалидный UTF-8;for i, r := range s: декодирует UTF-8 и выдаёт руны, гдеiэто байтовый индекс начала символа. Невалидные байты превращаются вutf8.RuneError(U+FFFD);utf8.RuneCountInString(s): считает кодовые точки без аллокации, а[]rune(s)создаёт новый срез и копирует данные, зато даёт доступ по индексу.
Строка не подходит, когда нужно работать с отдельными символами: разворот, обрезка до N символов, посимвольный разбор. Для этого переводят в []rune или идут по строке через range, а результат собирают в strings.Builder через WriteRune.
Сильный ответ добавит оговорку: руна тоже не всегда то, что человек видит как один символ. Эмодзи с модификатором цвета кожи или буква с комбинирующим знаком состоят из нескольких кодовых точек, и для них нужна нормализация из golang.org/x/text или разбор на графемы.
Где спотыкаются
Называют руну «символом в UTF-8». Руна это кодовая точка, а UTF-8 только способ записать её в виде от одного до четырёх байтов.
Считают, что len вернёт количество букв. Для ASCII это совпадает, для кириллицы уже нет.
Разворачивают строку, переставляя байты. Кириллица и эмодзи после этого превращаются в мусор.