Ответ
В Go строка (string
) — это неизменяемая (immutable) последовательность байт. Обычно эти байты представляют текст в кодировке UTF-8, что позволяет эффективно работать с символами Unicode.
Ключевые особенности:
Неизменяемость (Immutability)
- После создания строки её содержимое нельзя изменить. Любая операция, которая "модифицирует" строку (например, конкатенация), на самом деле создает новую строку в памяти.
- Это делает строки безопасными для одновременного использования в нескольких горутинах без необходимости синхронизации.
Представление в памяти
- Строка в Go — это легковесная структура, состоящая из указателя на массив байт и длины.
type StringHeader struct { Data uintptr; Len int }
- Строка в Go — это легковесная структура, состоящая из указателя на массив байт и длины.
Длина (
len()
) vs. Количество символов- Встроенная функция
len(s)
возвращает количество байт в строке, а не количество символов (рун). - Для подсчета символов (рун) необходимо использовать
utf8.RuneCountInString(s)
.
- Встроенная функция
Итерация по строке
- Итерация с помощью
for...range
происходит по рунам (символам Unicode), а не по байтам. Это самый удобный и правильный способ обхода строки, содержащей не-ASCII символы.
- Итерация с помощью
Практический пример:
package main
import (
"fmt"
"unicode/utf8"
)
func main() {
s := "Привет, мир!"
// len() возвращает количество байт
fmt.Printf("Длина в байтах: %dn", len(s)) // Вывод: 22 (кириллица занимает 2 байта на символ)
// utf8.RuneCountInString() возвращает количество символов (рун)
fmt.Printf("Длина в рунах (символах): %dn", utf8.RuneCountInString(s)) // Вывод: 12
// Доступ по индексу дает байт, а не символ
fmt.Printf("Первый байт: %dn", s[0]) // Вывод: 208 (первый байт буквы 'П')
// Итерация с for...range происходит по рунам
fmt.Print("Символы: ")
for _, r := range s {
fmt.Printf("%c ", r)
}
// Вывод: П р и в е т , м и р !
}
Модификация строк
Поскольку строки неизменяемы, для их изменения нужно создать новую строку. Эффективнее всего это делать с помощью strings.Builder
или путем преобразования строки в срез рун []rune
.
// Неэффективно для множества операций
newStr := s + "!!"
// Эффективно
var builder strings.Builder
builder.WriteString(s)
builder.WriteString("!!")
newStr = builder.String()