Длина строки: байты vs символы
1. Критическая особенность Go
Строка в Go = последовательность байт, не символов.
s := "hello"
fmt.Println(len(s)) // 5 — количество БАЙТ, не символов
Функция len() возвращает длину в байтах.
2. ASCII строки (1 символ = 1 байт)
ascii := "hello"
fmt.Printf("Строка: %s\n", ascii)
fmt.Printf("len(): %d байт\n", len(ascii))
Вывод:
Строка: hello
len(): 5 байт
Совпадает: 5 символов = 5 байт.
3. Кириллица (1 символ = 2 байта)
cyrillic := "привет"
fmt.Printf("Строка: %s\n", cyrillic)
fmt.Printf("len(): %d байт\n", len(cyrillic))
fmt.Printf("Символов: %d\n", utf8.RuneCountInString(cyrillic))
Вывод:
Строка: привет
len(): 12 байт
Символов: 6
Расхождение: 6 символов, но 12 байт (6 × 2).
4. Эмодзи (1 символ = 4 байта)
emoji := "😀"
fmt.Printf("Строка: %s\n", emoji)
fmt.Printf("len(): %d байт\n", len(emoji))
fmt.Printf("Символов: %d\n", utf8.RuneCountInString(emoji))
Вывод:
Строка: 😀
len(): 4 байт
Символов: 1
1 эмодзи = 4 байта в UTF-8.
5. Таблица размеров символов
| Тип символа | Пример | Байт на символ | len() | Символов |
|---|---|---|---|---|
| ASCII | "hello" |
1 | 5 | 5 |
| Кириллица | "привет" |
2 | 12 | 6 |
| Яблоко | "🍎" |
3 | 3 | 1 |
| Эмодзи | "😀" |
4 | 4 | 1 |
| Иероглифы | "你好" |
3 | 6 | 2 |
Вывод: Размер символа варьируется от 1 до 4 байт.
6. Правильный подсчёт символов
❌ Неправильно: len()
s := "привет"
fmt.Println(len(s)) // 12 — это БАЙТЫ, не символы!
✅ Правильно: utf8.RuneCountInString()
s := "привет"
count := utf8.RuneCountInString(s)
fmt.Println(count) // 6 — правильное количество символов
Работает корректно для любых Unicode-символов.
7. Примеры с разными кодировками
Смешанная строка
mixed := "Hello мир 😀"
fmt.Printf("Строка: %s\n", mixed)
fmt.Printf("len(): %d байт\n", len(mixed))
fmt.Printf("Символов: %d\n", utf8.RuneCountInString(mixed))
Вывод:
Строка: Hello мир 😀
len(): 19 байт
Символов: 12
Разбор:
"Hello "→ 6 байт (6 ASCII)"мир"→ 6 байт (3 × 2)" "→ 1 байт"😀"→ 4 байта- Итого: 17 байт, 11 символов
Китайские иероглифы
chinese := "你好" // "Привет" по-китайски
fmt.Printf("len(): %d байт\n", len(chinese))
fmt.Printf("Символов: %d\n", utf8.RuneCountInString(chinese))
Вывод:
len(): 6 байт
Символов: 2
1 иероглиф = 3 байта.
8. Практический пример
text := "🍎🍊🍋" // 3 фрукта
fmt.Printf("Строка: %s\n", text)
fmt.Printf("len(): %d байт\n", len(text))
fmt.Printf("Символов: %d\n", utf8.RuneCountInString(text))
Вывод:
Строка: 🍎🍊🍋
len(): 12 байт
Символов: 3
Каждый фрукт = 4 байта.
9. Типичная ошибка
s := "привет"
// ❌ ОШИБКА: попытка обратиться к "символу"
for i := 0; i < len(s); i++ {
fmt.Printf("%c ", s[i]) // Выведет мусор!
}
Вывод: Байты UTF-8, не символы.
✅ Правильно: итерация по рунам
s := "привет"
for _, r := range s {
fmt.Printf("%c ", r) // п р и в е т
}
for range по строке итерирует по рунам, не байтам.
10. Сравнение функций
| Функция | Что возвращает | Применение |
|---|---|---|
len(s) |
Длина в байтах | Размер в памяти, работа с байтами |
utf8.RuneCountInString(s) |
Количество символов | Подсчёт видимых символов |
for range s |
Итерация по рунам | Обход символов |
11. Когда использовать что
len() — для байтов
// Проверка пустоты (быстро)
if len(s) == 0 {
fmt.Println("Пустая строка")
}
// Выделение памяти
buf := make([]byte, len(s))
utf8.RuneCountInString() — для символов
// Ограничение длины для пользователя
if utf8.RuneCountInString(username) > 20 {
fmt.Println("Имя слишком длинное")
}
// Подсчёт символов в тексте
count := utf8.RuneCountInString(message)
fmt.Printf("Введено символов: %d\n", count)
12. Итоги
✅ len(s) возвращает длину в байтах, не символах
✅ ASCII — 1 байт на символ
✅ Кириллица — 2 байта на символ
✅ Некоторые символы (🍎) — 3 байта
✅ Эмодзи — 4 байта на символ
✅ utf8.RuneCountInString(s) — правильный подсчёт символов
✅ for range итерирует по рунам, не байтам
⚠️ Будьте внимательны при работе с разными кодировками
Ключевое правило:
len(s) → байты (размер в памяти)
utf8.RuneCountInString(s) → символы (видимые знаки)
for range s → итерация по символам
Практический совет:
// ❌ Неправильно для Unicode
if len(name) > 10 { ... }
// ✅ Правильно
if utf8.RuneCountInString(name) > 10 { ... }