Встречается на 16% собеседований по Go

Как устроены строки в Go

Строки в Go — это неизменяемые последовательности байт, которые обычно интерпретируются как текст в кодировке UTF-8. Это означает, что после создания строки её содержимое нельзя изменить — любая операция, которая выглядит как изменение, на самом деле создаёт новую строку. Такая реализация обеспечивает безопасность при работе в многопоточных приложениях и эффективное использование памяти.

Как это работает

Внутренне строка в Go представляет собой структуру, состоящую из указателя на массив байт и длины. Байты хранятся в неизменяемом участке памяти, поэтому строки можно безопасно передавать между горутинами без дополнительной синхронизации. Индексация строки s[i] возвращает байт, а не символ, что часто приводит к путанице у новичков.

Кодировка UTF-8 является переменной длины: символы могут занимать от 1 до 4 байт. Например, латинские буквы и цифры занимают 1 байт, а большинство кириллических символов — 2 байта. Поэтому для корректной работы с текстом, содержащим не-ASCII символы, необходимо использовать тип rune (алиас для int32), который представляет один символ Unicode.

Пример

go
package main

import "fmt"

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

    // Доступ по индексу возвращает байт, а не символ
    fmt.Println(s[0]) // 208 — первый байт первого символа 'П'

    // Перебор строки по рунам (символам Unicode)
    for _, r := range s {
        fmt.Printf("%#U ", r)
    }
    // Вывод: U+041F U+0440 U+0438 U+0432 U+0435 U+0442 U+002C U+0020 U+043C U+0438 U+0440 U+0021
}

В этом примере видно, что s[0] возвращает число 208 — это первый байт двухбайтового символа 'П'. Для получения символов используется цикл for range, который автоматически декодирует UTF-8 и возвращает руны.

Подводные камни

  • Индексация по байтам: s[i] возвращает байт, поэтому при работе с не-ASCII текстом нужно использовать for range или преобразование в []rune.
  • Неизменяемость: Попытка изменить строку через s[i] = ... вызовет ошибку компиляции. Для изменения строки нужно создавать новую, например, с помощью strings.Builder или конкатенации.
  • Конкатенация: Частая конкатенация строк через + может быть неэффективной из-за создания новых строк. В циклах лучше использовать strings.Builder.
  • Преобразования: Преобразование string в []byte и обратно копирует данные, что может быть затратно для больших строк.

Когда использовать

Строки в Go — основной тип для работы с текстом. Они подходят для хранения сообщений, обработки данных, работы с сетевыми протоколами и файлами. Благодаря встроенной поддержке UTF-8, Go хорошо подходит для интернациональных приложений. Однако для интенсивных манипуляций с текстом (например, построение больших строк) стоит использовать strings.Builder или bytes.Buffer.

Коротко

  • Строка — неизменяемая последовательность байт, обычно в UTF-8.
  • Индексация возвращает байт, а не символ; для символов используйте for range или []rune.
  • Строки безопасны для конкурентного доступа, но операции изменения создают новые строки.
  • Для эффективной сборки строк используйте strings.Builder.
как отвечать на вопрос
пример собеседования
фреймворки на собеседовании
типичные вопросы junior
интервью вопросы и ответы