Каково внутреннее устройство и особенности строк в Go?

Ответ

Строка в Go — это неизменяемая (immutable) последовательность байт. Обычно эти байты представляют собой текст в кодировке UTF-8.

Внутренне строка представляет собой небольшую структуру, содержащую два поля:

// Это лишь концептуальное представление, не реальный код
type stringStruct struct {
    str unsafe.Pointer // указатель на начало последовательности байт в памяти
    len int            // количество байт в строке
}

Ключевые особенности:

  1. Неизменяемость: Любая операция, которая «изменяет» строку (например, конкатенация), на самом деле создает новую строку в памяти.
  2. Длина в байтах: Встроенная функция len(s) возвращает количество байт, а не символов (рун). Для многобайтовых символов (например, кириллицы) это различие существенно.
  3. Итерация по рунам: Цикл for range по строке итерируется по рунам (Unicode code points), а не по байтам. Это правильный способ работать с символами в UTF-8.
  4. Нулевое значение: Нулевое значение для строки — это пустая строка "".

Пример:

s := "Привет"

// len() возвращает количество БАЙТ
fmt.Println(len(s)) // Вывод: 12 (каждая кириллическая буква в UTF-8 занимает 2 байта)

// Конвертация в срез рун для получения количества СИМВОЛОВ
fmt.Println(len([]rune(s))) // Вывод: 6

// for range итерируется по рунам
for index, r := range s {
    fmt.Printf("Индекс байта: %d, Руна: %cn", index, r)
}
// Вывод:
// Индекс байта: 0, Руна: П
// Индекс байта: 2, Руна: р
// Индекс байта: 4, Руна: и
// ...