Модуль
1Hello, World!2Переменные в Go3Целые числа4Строки и руны← вы здесь5float64 и числа с плавающей точкой6if, switch, for7bool и логические операторы8Константы и iota9Пакет fmt: форматирование вывода
Урок 4~15 минут

Строки и руны

Строки — это байты, не символы

В Go строка — это неизменяемый срез байт. Это важно понять сразу:

go
s := "Hello"
fmt.Println(len(s))  // 5 — байт, не символов

Для ASCII (английские буквы, цифры) 1 символ = 1 байт. Но для кириллицы, иероглифов и emoji — нет:

go
s := "Привет"
fmt.Println(len(s))            // 12 — байт (каждая буква = 2 байта в UTF-8)
fmt.Println(len([]rune(s)))    // 6  — символов
Байты vs символы
Ctrl+Enter
1

Два вида строковых литералов

Двойные кавычки — интерпретируемые строки:

go
s := "Hello\nWorld"  // \n — реальный перенос строки
s2 := "Tab:\there"   // \t — реальная табуляция

Обратные кавычки — raw string, буквально:

go
s := `Hello\nWorld`  // \n — это два символа \ и n, не перенос
json := `{
    "name": "Alice",
    "age": 30
}`
regex := `\d+\.\d+`  // регулярка без ада с экранированием

Raw-строки удобны для JSON, SQL-запросов, регулярных выражений — везде, где много обратных слэшей.


Rune — символ Unicode

rune — это псевдоним для int32. Хранит Unicode code point:

go
var r rune = 'А'           // 1040 — код кириллической А
fmt.Printf("%c %d\n", r, r)  // А 1040

Итерация по строке через range автоматически даёт руны:

go
s := "Hi, мир!"
for i, r := range s {
    fmt.Printf("байт[%d]: %c (U+%04X)\n", i, r, r)
}
// байт[0]: H (U+0048)
// байт[1]: i (U+0069)
// байт[2]: , (U+002C)
// байт[3]:   (U+0020)
// байт[4]: м (U+043C)   ← индекс 4, но следующий будет 6!
// байт[6]: и (U+0438)   ← пропрыг через 2 байта
// ...

Обрати внимание: i — это байтовый индекс, а не порядковый номер символа.

Если нужны порядковые индексы — конвертируй:

go
runes := []rune(s)
for i, r := range runes {
    fmt.Printf("символ[%d]: %c\n", i, r)  // теперь i = 0,1,2,...
}
range по строке: байтовые индексы
Ctrl+Enter
1

Срезы строк — ловушка с Unicode

go
s := "Hello"
fmt.Println(s[1:3])  // "el" — OK, ASCII
 
s2 := "Привет"
fmt.Println(s2[0:2])  // "П" — OK, первый кириллический символ = 2 байта
fmt.Println(s2[0:1])  // ПЛОХО: разрезает многобайтовый символ → некорректный UTF-8

Безопасный способ — через []rune:

go
s := "Привет"
runes := []rune(s)
fmt.Println(string(runes[0:3]))  // "При" — первые 3 символа

Конкатенация

Простая (через +):

go
name := "Alice"
greeting := "Hello, " + name + "!"

В цикле — используй strings.Builder:

go
import "strings"
 
var b strings.Builder
for i := 0; i < 1000; i++ {
    b.WriteString("Go")
    b.WriteByte(' ')
}
result := b.String()

Почему не += в цикле? Каждый += создаёт новую строку в памяти — это O(n²). Builder накапливает в буфер — O(n).

strings.Builder — эффективная конкатенация
Ctrl+Enter
1

Пакет strings

Всё для работы со строками:

go
import "strings"
 
s := "Hello, World!"
 
strings.ToUpper(s)            // "HELLO, WORLD!"
strings.ToLower(s)            // "hello, world!"
strings.Contains(s, "World") // true
strings.HasPrefix(s, "Hello") // true
strings.HasSuffix(s, "!")    // true
strings.Count(s, "l")        // 3
strings.Replace(s, "World", "Go", 1)  // "Hello, Go!"
strings.TrimSpace("  hi  ")  // "hi"
strings.Split("a,b,c", ",")  // ["a", "b", "c"]
strings.Join([]string{"a","b","c"}, "-")  // "a-b-c"
Пакет strings — основные функции
Ctrl+Enter
1

Пакет strconv — числа ↔ строки

go
import "strconv"
 
// int → string
s := strconv.Itoa(42)       // "42"
 
// string → int
n, err := strconv.Atoi("42")  // 42, nil
if err != nil { /* не число */ }
 
// float → string
f := strconv.FormatFloat(3.14, 'f', 2, 64)  // "3.14"
 
// string → float
f2, _ := strconv.ParseFloat("3.14", 64)     // 3.14

fmt.Sprintf тоже работает, но strconv быстрее — нет парсинга формата.


fmt.Sprintf — форматирование строк

go
name, age := "Alice", 30
s := fmt.Sprintf("Имя: %s, Возраст: %d", name, age)
 
// Полезные форматы:
fmt.Sprintf("%d", 255)          // "255"     десятичный int
fmt.Sprintf("%x", 255)          // "ff"      hex
fmt.Sprintf("%b", 255)          // "11111111" binary
fmt.Sprintf("%f", 3.14)         // "3.140000"
fmt.Sprintf("%.2f", 3.14)       // "3.14"
fmt.Sprintf("%v", []int{1,2,3}) // "[1 2 3]" любой тип
fmt.Sprintf("%T", 42)           // "int"     тип переменной
fmt.Sprintf("%q", "hello")      // `"hello"` с кавычками
fmt.Sprintf — форматирование строк
Ctrl+Enter
1

В следующем уроке разберём float64 — как Go хранит дробные числа, почему 0.1 + 0.2 ≠ 0.3 и как с этим жить.

len(s) возвращает байты, не символы. Для итерации по символам используй range — он автоматически декодирует UTF-8 в руны.
Байты vs Руны
len(s) — байт
12
len([]rune(s)) — символов
6
Байт на символ
~2.0
Символы (руны):
П
2B
U+041F
р
2B
U+0440
и
2B
U+0438
в
2B
U+0432
е
2B
U+0435
т
2B
U+0442
Байты в памяти (UTF-8):
D0
0
9F
1
D1
2
80
3
D0
4
B8
5
D0
6
B2
7
D0
8
B5
9
D1
10
82
11
Операции со строками
s := "Привет"
len(s) = 12  // байт
💡 len() считает байты. "Привет" занимает 12 байт, но содержит 6 символа/ов.
Управляющие последовательности
\nПеренос строки (newline)
\tТабуляция
\"Кавычка внутри строки
\\Обратный слэш
\rВозврат каретки (Windows newline)
\u0041Unicode: A (U+0041)
\x41Hex: A (0x41 = 65)
🎯
Миссия 1 из 5
Сколько байт вернёт len("Привет") в Go?