Что представляет собой строка (string) в Go и каковы её ключевые особенности?

Ответ

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

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

  1. Неизменяемость (Immutability)

    • После создания строки её содержимое нельзя изменить. Любая операция, которая "модифицирует" строку (например, конкатенация), на самом деле создает новую строку в памяти.
    • Это делает строки безопасными для одновременного использования в нескольких горутинах без необходимости синхронизации.
  2. Представление в памяти

    • Строка в Go — это легковесная структура, состоящая из указателя на массив байт и длины.

      type StringHeader struct { Data uintptr; Len int }
  3. Длина (len()) vs. Количество символов

    • Встроенная функция len(s) возвращает количество байт в строке, а не количество символов (рун).
    • Для подсчета символов (рун) необходимо использовать utf8.RuneCountInString(s).
  4. Итерация по строке

    • Итерация с помощью for...range происходит по рунам (символам Unicode), а не по байтам. Это самый удобный и правильный способ обхода строки, содержащей не-ASCII символы.

Практический пример:

package main

import (
    "fmt"
    "unicode/utf8"
)

func main() {
    s := "Привет, мир!"

    // len() возвращает количество байт
    fmt.Printf("Длина в байтах: %dn", len(s)) // Вывод: 22 (кириллица занимает 2 байта на символ)

    // utf8.RuneCountInString() возвращает количество символов (рун)
    fmt.Printf("Длина в рунах (символах): %dn", utf8.RuneCountInString(s)) // Вывод: 12

    // Доступ по индексу дает байт, а не символ
    fmt.Printf("Первый байт: %dn", s[0]) // Вывод: 208 (первый байт буквы 'П')

    // Итерация с for...range происходит по рунам
    fmt.Print("Символы: ")
    for _, r := range s {
        fmt.Printf("%c ", r)
    }
    // Вывод: П р и в е т ,   м и р ! 
}

Модификация строк

Поскольку строки неизменяемы, для их изменения нужно создать новую строку. Эффективнее всего это делать с помощью strings.Builder или путем преобразования строки в срез рун []rune.

// Неэффективно для множества операций
newStr := s + "!!"

// Эффективно
var builder strings.Builder
builder.WriteString(s)
builder.WriteString("!!")
newStr = builder.String()