Ответ
Строка в Go — это неизменяемая (immutable) последовательность байт. Обычно эти байты представляют собой текст в кодировке UTF-8.
Внутренне строка представляет собой небольшую структуру, содержащую два поля:
// Это лишь концептуальное представление, не реальный код
type stringStruct struct {
str unsafe.Pointer // указатель на начало последовательности байт в памяти
len int // количество байт в строке
}
Ключевые особенности:
- Неизменяемость: Любая операция, которая «изменяет» строку (например, конкатенация), на самом деле создает новую строку в памяти.
- Длина в байтах: Встроенная функция
len(s)возвращает количество байт, а не символов (рун). Для многобайтовых символов (например, кириллицы) это различие существенно. - Итерация по рунам: Цикл
for rangeпо строке итерируется по рунам (Unicode code points), а не по байтам. Это правильный способ работать с символами в UTF-8. - Нулевое значение: Нулевое значение для строки — это пустая строка
"".
Пример:
s := "Привет"
// len() возвращает количество БАЙТ
fmt.Println(len(s)) // Вывод: 12 (каждая кириллическая буква в UTF-8 занимает 2 байта)
// Конвертация в срез рун для получения количества СИМВОЛОВ
fmt.Println(len([]rune(s))) // Вывод: 6
// for range итерируется по рунам
for index, r := range s {
fmt.Printf("Индекс байта: %d, Руна: %cn", index, r)
}
// Вывод:
// Индекс байта: 0, Руна: П
// Индекс байта: 2, Руна: р
// Индекс байта: 4, Руна: и
// ... Ответ 18+ 🔞
Слушай, а вот тебе про строки в Go, чтобы ты не думал, что это какая-то простая хуйня. Это не просто текст, это, блядь, неизменяемая последовательность байтов, обычно в UTF-8. Представь себе, как будто ты вырезал буквы из стали — переделать нихуя не получится, только новый кусок отлить.
Внутри это выглядит как маленькая хитрая коробочка с двумя пиздюлинами:
// Это лишь концептуальное представление, не реальный код
type stringStruct struct {
str unsafe.Pointer // указатель на начало последовательности байт в памяти
len int // количество байт в строке
}
А теперь главное, чтобы ты не обосрался с подводными камнями:
- Неизменяемость, ёпта! Если ты думаешь, что
s += "!"меняет строку — хуй там! Она создаёт новую, старую выкидывает, и память ебёт почём зря. Мартышлюшка. - Длина в байтах, а не в символах!
len(s)— это не количество букв, а количество байтов. Для русского слова это, блядь, в два раза больше. Чистая ловушка для распиздяев. - Итерация по рунам — это правильно. Цикл
for rangeидёт по нормальным символам (рунам), а не по байтам. Это твой друг, запомни. - Нулевое значение — это просто пустая строка
"". Ничего сложного.
Смотри пример, чтобы не быть мудаком:
s := "Привет"
// len() возвращает количество БАЙТ
fmt.Println(len(s)) // Вывод: 12 (каждая кириллическая буква в UTF-8 занимает 2 байта)
// Конвертация в срез рун для получения количества СИМВОЛОВ
fmt.Println(len([]rune(s))) // Вывод: 6
// for range итерируется по рунам
for index, r := range s {
fmt.Printf("Индекс байта: %d, Руна: %cn", index, r)
}
// Вывод:
// Индекс байта: 0, Руна: П
// Индекс байта: 2, Руна: р
// Индекс байта: 4, Руна: и
// ...
Вот и вся магия. Главное — не путай байты с рунами, а то получишь ебанистический баг, который будешь искать полдня. В рот меня чих-пых!