Go: Строки

23 вопросов

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

Строка - неизменяемая последовательность байт. Внутри это структура с указателем на массив байт и длиной (length). Строка не обязана быть валидным UTF-8; для текста в UTF-8 итерация по рунам делается через for _, r := range s.

Открыть отдельно →
2 Строки в Go изменяемые или неизменяемые?

Неизменяемые. После создания нельзя изменить байты строки. Операции вроде конкатенации или среза создают новую строку. Поэтому частые конкатенации в цикле лучше делать через strings.Builder.

Открыть отдельно →
3 Когда использовать strings.Builder?

Когда нужно много раз добавлять части к строке (например, в цикле). Builder накапливает байты в буфере и выдаёт строку через String() без лишних копирований. Эффективнее, чем конкатенация через + или += в цикле.

Открыть отдельно →
4 Почему конкатенация через + не всегда лучший выбор?

Каждый s + x создаёт новую строку и копирует данные. В цикле это O(n^2) по времени и лишние аллокации. Для однократной конкатенации двух строк + нормален; для накопления результата лучше strings.Builder.

Открыть отдельно →
5 В чём минусы использования += для строк в цикле?

s += part каждый раз создаёт новую строку: старую копируют, добавляют part, старую отбрасывают. Итоговая сложность квадратичная, много аллокаций. Используйте strings.Builder и WriteString для накопления.

Открыть отдельно →
6 Как посчитать количество символов (рун) в строке?

Количество рун (кодовых точек): utf8.RuneCountInString(s). len(s) даёт число байт. Для ASCII строки оба совпадают; для UTF-8 с многобайтовыми символами len больше.

Открыть отдельно →
7 Что возвращает len() для строки - байты или символы?

len(s) возвращает длину в байтах, не количество символов. Для UTF-8 количество символов: utf8.RuneCountInString(s) или len([]rune(s)) (последний аллоцирует срез рун).

Открыть отдельно →
8 Как итерироваться по строке по символам (рунам)?

for _, r := range s даёт руны (кодовые точки) и корректно обрабатывает многобайтовые UTF-8 символы. Индекс в for i, r := range s - смещение в байтах начала руны. По индексу байта s[i] даёт байт (uint8).

Открыть отдельно →
9 Как изменить символ в строке?

Строки неизменяемы, поэтому "на месте" нельзя. Обычно: преобразовать в []rune, изменить элемент, обратно string(runes). Либо собрать новую строку через strings.Builder или срезы: s[:i] + newChar + s[i+width:] (для байтов нужен размер руны).

Открыть отдельно →
10 Как преобразовать string в []byte и обратно?

[]byte(s) и string(b) - преобразования между строкой и срезом байт. Под капотом при копировании данных может использоваться копирование; не изменяйте полученный []byte, если строка должна остаться неизменной (не гарантируется копия при оптимизациях в будущем). Для явной копии: b := append([]byte(nil), s...).

Открыть отдельно →
11 Когда использовать []rune(s)?

Когда нужен произвольный доступ по индексу символа (руны) или изменение "символов". []rune(s) разбирает UTF-8 и создаёт срез кодовых точек; аллокация и копирование. Для итерации достаточно for _, r := range s без среза рун.

Открыть отдельно →
12 Какие функции из strconv для работы со строками чисел?

strconv.Atoi(s) - строка в int; strconv.ParseInt(s, 10, 64) - с основанием и размером; strconv.Itoa(i) - int в строку; ParseFloat, FormatBool и др. Все возвращают ошибку при неверном формате.

Открыть отдельно →
13 Как правильно работать с кириллицей в строках?

Go хранит строки в UTF-8. Кириллица - многобайтовые руны. Используйте for _, r := range s для обхода по символам; len(s) даст байты. Для среза "по символам" переведите в []rune, срежьте, обратно string(). Функции strings, utf8 работают с UTF-8.

Открыть отдельно →
14 Сколько памяти занимает пустая строка?

Пустая строка "" - это структура строки (указатель + длина). Размер заголовка строки фиксирован (обычно 16 байт на 64-битной платформе). Данных нет, указатель может указывать на пустой или общий буфер; не аллоцируется отдельная память под "пустые" данные.

Открыть отдельно →
15 Что даёт пакет strings?

Функции для поиска и замены: Contains, HasPrefix, Split, Join, Replace, Trim, Fields; сравнение Compare; Builder для накопления; Reader для чтения строки как io.Reader. Работа идёт с байтами; для UTF-8 с символами - utf8, runes.

Открыть отдельно →
16 Go использует UTF-8? Как?

Да. Исходный код в UTF-8; строки по умолчанию - последовательности байт в UTF-8. Литералы рун и строк в UTF-8. range по строке даёт руны (кодовые точки). Пакеты unicode, utf8 для проверки и разбора UTF-8.

Открыть отдельно →
17 Как получить i-й символ строки?

По индексу байта: s[i] - один байт (тип byte). Для i-й руны (символа) нужно итерацию или срез: []rune(s)[i] - но это аллоцирует срез; либо перебор for i, r := range s и счётчик. Для одной руны по индексу байта: r, _ := utf8.DecodeRuneInString(s[offset:]).

Открыть отдельно →
18 bytes.Buffer vs strings.Builder - когда что?

strings.Builder предназначен для построения строки (метод String() возвращает строку, без копирования при повторном вызове в Go 1.15+). bytes.Buffer - для накопления байт; подходит и для строк, и для бинарных данных, реализует больше интерфейсов (io.Reader, io.Writer и т.д.). Для только строк предпочтителен Builder.

Открыть отдельно →
19 Что такое strings.Reader?

strings.Reader реализует io.Reader, io.ReaderAt, io.Seeker и др., читая из строки. Удобно, когда API ожидает io.Reader, а данные уже в строке. Создание: strings.NewReader(s).

Открыть отдельно →
20 Когда использовать fmt.Sprintf для строк?

Когда нужно отформатировать строку по шаблону: подстановка чисел, отступы, несколько значений. Пример: fmt.Sprintf("id=%d", id). Для простой конкатенации часто достаточно + или strconv. Для накопления в цикле - strings.Builder и fmt.Fprintf(builder, ...).

Открыть отдельно →
21 Есть ли в Go интернирование строк?

Спецификация не гарантирует интернирование. Компилятор и рантайм могут объединять одинаковые строковые литералы. Не стоит полагаться на то, что s1 == s2 по указателю; для сравнения содержимого всегда используйте == строк или strings.Compare.

Открыть отдельно →
22 Как сравниваются строки в Go?

Операторы == и != сравнивают строки побайтово. Строки сравнимы (comparable). Для лексикографического порядка: strings.Compare(a, b) возвращает -1, 0 или 1. Регистронезависимое сравнение: strings.EqualFold(a, b).

Открыть отдельно →
23 string vs []byte - что быстрее и когда что использовать?

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

Открыть отдельно →
🧠Квиз 🏆Лидеры 🎯Собесед. 📖Вопросы 📚База зн.