Материал проходит вычитку — возможны неточности.
Урок 7 из 118

Подстроки за O(1)

Сергей заказал автокомплит имён по первым буквам. Уже на тестовых данных поле выдачи показывало мусор: обрезок имени «привет» разрывал букву пополам. Фичу вернули на доработку.

Главная мысль

подстрока не копирует байты и делается мгновенно, но держит весь исходный массив живым и режет строго по границам байтов.

У строки есть второе ключевое свойство — неизменяемость. Строку нельзя изменить после создания:

s := "hello"
s[0] = 'H' // cannot assign to s[0] — ошибка компиляции

Неизменяемость — не ограничение ради чистоты, а то, что делает строки безопасными для свободного расшаривания. Когда несколько мест в программе держат одну и ту же строку, никто из них не может испортить данные остальным.

Срез — новый заголовок, не копия

У неизменяемости есть приятное следствие: взятие подстроки не копирует байты. path[5:] просто создаёт новый заголовок, указывающий в тот же массив.

Go

Подстрока делается за O(1) независимо от длины исходной строки. Можно резать гигабайтный текст на куски, и каждый кусок будет дёшевым.

Цена дешёвого среза

Плата за это две. Первая — про память: исходный массив не может быть собран сборщиком мусора, пока жива хотя бы одна подстрока, указывающая в него.

big := readHugeFile()  // строка на гигабайт
head := big[:10]       // отрезали 10 байт
// big не освободится, пока жив head — вся гигабайтная строка живёт дальше

Вторая плата — про границы. Резать можно только по границам байтов. Границы символов Go за вас не проверяет, и срез, попавший в середину многобайтового символа, даст битую строку — без паники, просто с мусором внутри:

Go
В следующем уроке

Вы узнаете:

  • как «отвязать» срез от большого исходника копированием
  • как работать с байтовыми индексами в горячем коде
Задание · вопросы

Проверьте себя

Вопрос 1 из 3

Валидация «Полки» срезает имя по байтовому индексу: s := "привет"; fmt.Println(s[1:4]). Что выведет программа?

Вопрос 2 из 3

Что происходит при взятии подстроки name := path[5:]?

Вопрос 3 из 3

Почему гигабайтная строка big не освобождается, пока жив её маленький срез head := big[:10]?

Итоги

Срез — это новый заголовок на тот же массив: O(1), без копирования. Цена: исходный массив держится в памяти, пока жив хотя бы один срез, а границы символов никто не проверяет.

Наш сайт собирает куки. Чтобы тебе было удобнее им пользоваться. Нажимая на кнопку, ты даёшь разрешение собирать куки