Строки и байты
Чему вы научитесь:
- объяснять, почему
len("привет")возвращает12, а не6; - отличать байт от руны и перебирать строку по символам;
- собирать новую строку из частей, раз старую изменить нельзя;
- искать, разбивать и склеивать строки функциями пакета
strings.

Представьте ряд фишек с буквами, как в настольной игре со словами. Каждая фишка — один байт: маленькое число от 0 до 255, а буква на ней — лишь способ это число показать. Строка в Go устроена как такой ряд: это байты, в которых записан текст. Латинская буква, цифра или пробел занимают одну фишку, а буква кириллицы — две.
Из этой картинки следуют два сюрприза. Строку можно индексировать, как срез: s[0] — её первый элемент. Но результат выглядит неожиданно:
- первый элемент строки
"Go"печатается числом; - длина строки
"Привет"вдвое больше числа букв в ней.
package main
import "fmt"
func main() {
s := "Go"
fmt.Println(len(s), s[0]) // 2 71
fmt.Println(len("Привет")) // 12
}Давайте разберём вывод:
len(s)возвращает2: в"Go"две латинские буквы, по фишке на каждую.s[0]возвращает71— число с первой фишки.len("Привет")возвращает12: в слове шесть букв по две фишки.
Строка из байтов
Строка в Go хранит последовательность байтов, в которых текст записан в кодировке UTF-8. Кодировка — это правило, по которому каждая буква превращается в байты. В UTF-8 латинская буква, цифра или пробел занимают один байт, а буква кириллицы — два.
Функция len возвращает число байтов, а не букв: она считает фишки. Поэтому в строке "Привет" шесть букв и двенадцать байтов.
Этот вопрос часто задают на собеседовании: «Что вернёт len("привет")?» Правильный ответ — 12, потому что len у строки всегда считает байты.
Индекс возвращает байт
Индекс s[i] возвращает один байт — значение типа byte:
- тип
byte— другое имя типаuint8, целое число от0до255; - поэтому
fmt.Printlnпечатает не буквуG, а её код71; - с буквой байт сравнивают через одинарные кавычки:
s[0] == 'G'даётtrue.
Нажимайте кнопку и читайте строку "Go Привет" по байту, как s[i]: следите, сколько байтов занимают латинская буква, пробел и буква кириллицы.
Строка хранит байты UTF-8. Нажмите кнопку, чтобы читать её по одному байту, как это делает s[i].
Границы индекса такие же, как у среза:
- индексы идут от
0доlen(s) - 1; - индекс за пределами строки вызывает панику;
- у пустой строки
""длина0, и паникует любой индекс.
Строку нельзя изменить
Строки в Go неизменяемы: байты созданной строки больше не меняются. Здесь картинка с фишками перестаёт работать: настоящую фишку можно снять и заменить, а байт строки — нельзя.
Что можно и чего нельзя:
- присвоить новое значение элементу
s[i]не получится; - переменной можно присвоить другую строку целиком;
- новую строку собирают оператором
+из частей старой.
Новая строка из частей
s := "Go"
t := "g" + s[1:]
fmt.Println(t, s) // go GoДавайте разберём пример по строкам:
s := "Go"создаёт строку из двух байтов.t := "g" + s[1:]собирает новую строку. Выражениеs[1:]берёт часть строки по тем же правилам, что и срез среза, и возвращает строку. Байты с индекса1до конца попадают вtвместе с буквой"g".fmt.Println(t, s)печатаетgo Go. Самаsне изменилась: оператор+создаёт новую строку из байтов обеих частей.
Границы в s[1:] тоже считаются в байтах, а не в буквах. Для "Go" это одно и то же. А "Привет"[1:] начинается с середины буквы П: такой срез режет букву пополам, и программа напечатает на её месте непонятный знак.
Копирование и сравнение
Две операции работают со строкой целиком:
- присваивание
t := sне копирует байты: обе переменные видят один и тот же текст, и ни одна не может его испортить; - оператор
==сравнивает две строки: он сравнивает их байты по порядку.
Частая ошибка
Первую букву строки заменяют присваиванием по индексу:
s := "hello"
s[0] = 'H' // ✗cannot assign to s[0] (neither addressable nor a map index expression)Компилятор отклоняет присваивание, потому что строка неизменяема, и программа не собирается. Новую строку собирают из частей: s = "H" + s[1:].
Главное
- Строка — ряд байтов в кодировке UTF-8;
lenсчитает байты, поэтомуlen("привет")равно12. s[i]возвращает один байт типаbyte: число от0до255, а не букву.- Срез строки
s[1:]тоже режет по байтам и может разрезать букву пополам. - Строку изменить нельзя:
s[0] = 'H'не компилируется, а новую строку собирают из частей через+.
Подпишись, чтобы пройти курс
Курс бесплатный. Войди через Telegram и подпишись на канал — откроются все уроки.