Что такое руны в Go и как работать с Unicode-символами в строках?

Ответ

В Go строка (string) — это неизменяемая последовательность байт. Это эффективно, но создает сложности при работе с языками, где символы могут занимать больше одного байта (например, кириллица, иероглифы, эмодзи).

Для корректной работы с такими символами в Go используется тип rune.

Ключевые концепции:

  • rune — это псевдоним (alias) для типа int32. Он представляет собой один кодовый пункт (code point) Unicode.
  • Строка — это UTF-8 закодированная последовательность байт. Один символ может состоять из 1-4 байт.

Преобразование и итерация:

Чтобы работать со строкой как с последовательностью символов (рун), а не байт, ее нужно преобразовать в срез рун []rune.

s := "Привет, мир! 👋"

// Преобразование строки в срез рун
runes := []rune(s)

// len() для строки вернет количество байт, а для среза рун - количество символов
fmt.Printf("Байт в строке: %dn", len(s))      // Выведет: 25
fmt.Printf("Рун (символов) в строке: %dn", len(runes)) // Выведет: 15

// Обратное преобразование
newS := string(runes)
fmt.Println(newS)

Правильная итерация по символам:

Использование range для итерации по строке — это идиоматичный и правильный способ, так как range автоматически декодирует UTF-8 символы в руны.

s := "Go-рулит"
// range возвращает индекс начала руны в байтах и саму руну
for i, r := range s {
    fmt.Printf("Индекс байта: %d, Символ: %cn", i, r)
}

Вывод:

  • Для получения количества символов используйте utf8.RuneCountInString(s) или len([]rune(s)).
  • Для итерации по символам всегда используйте for ... range.