В чем ключевые различия между строкой (`string`) и срезом байтов (`[]byte`) в Go?

Ответ

Строка (string) и срез байтов ([]byte) в Go на первый взгляд похожи, но имеют фундаментальные различия, знание которых критически важно для производительности и корректности программы.

Ключевые различия:

  1. Изменяемость (Mutability)

    • string: Неизменяемый (immutable). После создания строки изменить её содержимое невозможно. Любая операция, которая "изменяет" строку (например, конкатенация), на самом деле создает новую строку в памяти.
    • []byte: Изменяемый (mutable). Элементы среза байтов можно изменять по индексу после его создания.
  2. Предназначение (Purpose)

    • string: Предназначен для хранения текстовых данных, которые обычно представлены в кодировке UTF-8. Многие строковые функции в стандартной библиотеке (например, range по строке) работают с учетом UTF-8 рун.
    • []byte: Универсальный тип для работы с произвольными бинарными данными: чтение файлов, сетевые пакеты, буферы и т.д.
  3. Преобразование (Conversion)

    • Преобразование string в []byte и наоборот ([]byte(myString) и string(myBytes)) создает копию данных. Это важный аспект производительности: частые преобразования могут привести к лишним выделениям памяти и нагрузке на сборщик мусора.

Пример:

_func_ main() {
    // 1. Неизменяемость строки
    s1 := "hello"
    // s1[0] = 'H' // Эта строка вызовет ошибку компиляции: cannot assign to s1[0]

    // 2. Изменяемость среза байтов
    b := []byte(s1) // Создается копия данных
    b[0] = 'H'      // Это работает, т.к. срез изменяем

    // 3. Преобразование обратно в строку создает еще одну копию
    s2 := string(b) 

    fmt.Println("Original string:", s1) // "hello"
    fmt.Println("Modified slice:", string(b)) // "Hello"
    fmt.Println("New string:", s2)      // "Hello"
}

Вывод: Используйте string для текстовых констант и данных, которые не требуют изменений. Используйте []byte для данных, которые нужно модифицировать, или для работы с бинарными потоками. Избегайте ненужных преобразований между этими типами в критичных к производительности участках кода.