Подробная механика работы цикла for: порядок выполнения и отладка
Порядок выполнения компонентов цикла
При запуске цикла for компоненты выполняются в строгом порядке:
Шаг 1: Инициализация (init) — выполняется один раз перед началом цикла
for i := 1; i <= 5; i++ {
// ↑ инициализация: i := 1 (выполняется один раз)
}
Шаг 2: Проверка условия (condition) — выполняется перед каждой итерацией
for i := 1; i <= 5; i++ {
// ↑ проверка: i <= 5 перед входом в тело
}
Шаг 3: Выполнение тела цикла — если условие истинно
for i := 1; i <= 5; i++ {
fmt.Println(i) // ← тело цикла
}
Шаг 4: Постусловие (post) — выполняется после каждой итерации
for i := 1; i <= 5; i++ {
// ↑ приращение: i++ после тела
}
Шаг 5: Возврат к шагу 2 — снова проверка условия
Пример с остановом при i <= 0
for i := 1; i <= 0; i++ {
fmt.Println(i)
}
// Порядок: init (i=1) → condition (1<=0 = false) → цикл не выполнится
Условие 1 <= 0 ложно, поэтому тело цикла ни разу не выполняется.
Пример с остановом при i <= 1
for i := 1; i <= 1; i++ {
fmt.Println(i)
}
// Порядок:
// 1. init: i=1
// 2. condition: 1<=1 = true → вход в тело
// 3. body: печать "1"
// 4. post: i++ (теперь i=2)
// 5. condition: 2<=1 = false → выход из цикла
Цикл выполнится один раз, напечатает 1, затем завершится.
Область видимости счётчика
Счётчик внутри for
Переменная, объявленная в init, видна только внутри цикла:
for i := 10; i <= 12; i++ {
fmt.Printf("i = %d (видна здесь)\n", i)
}
// fmt.Println(i) // ❌ ошибка: undefined: i
Счётчик снаружи for
Если объявить переменную до цикла, она доступна везде:
index := 1
fmt.Println("До цикла:", index) // 1
for ; index <= 1; index++ {
fmt.Println("Внутри:", index) // 1
}
fmt.Println("После цикла:", index) // 2
Порядок:
index = 1(до цикла)- Проверка:
1 <= 1→ истина - Печать “Внутри: 1”
- Приращение:
index++→index = 2 - Проверка:
2 <= 1→ ложь → выход - Печать “После цикла: 2”
Работа с дебаггером в VS Code
Подготовка проекта
Шаг 1: Инициализация модуля
go mod init example.com/loops
Шаг 2: Установка точки останова (breakpoint)
Кликните слева от номера строки — появится красная точка:
sum := 0 // ← поставьте точку останова здесь
for i := 1; i <= 10; i++ {
sum += i
}
Шаг 3: Запуск отладки
- Откройте панель Run and Debug (Ctrl+Shift+D)
- Нажмите “Run and Debug”
- Выберите “Go”
Пошаговое выполнение (Step Over)
Step Over (F10) — выполнить текущую строку и перейти к следующей.
Пример отладки суммы 1+2+3:
sum := 0 // ← точка останова
for i := 1; i <= 3; i++ {
sum += i
}
fmt.Println("Сумма:", sum)
Пошаговая трассировка:
| Шаг | Строка | Действие | sum | i | Описание |
|---|---|---|---|---|---|
| 1 | sum := 0 |
Инициализация | 0 |
— | Переменная создана |
| 2 | for i := 1 |
Init цикла | 0 |
1 |
Счётчик создан |
| 3 | i <= 3 |
Проверка условия | 0 |
1 |
1<=3 = true |
| 4 | sum += i |
Тело цикла | 1 |
1 |
0+1=1 |
| 5 | i++ |
Post | 1 |
2 |
Приращение |
| 6 | i <= 3 |
Проверка условия | 1 |
2 |
2<=3 = true |
| 7 | sum += i |
Тело цикла | 3 |
2 |
1+2=3 |
| 8 | i++ |
Post | 3 |
3 |
Приращение |
| 9 | i <= 3 |
Проверка условия | 3 |
3 |
3<=3 = true |
| 10 | sum += i |
Тело цикла | 6 |
3 |
3+3=6 |
| 11 | i++ |
Post | 6 |
4 |
Приращение |
| 12 | i <= 3 |
Проверка условия | 6 |
4 |
4<=3 = false → выход |
| 13 | fmt.Println |
Печать | 6 |
— | Вывод “Сумма: 6” |
Просмотр переменных
В панели Variables → Local отображаются текущие значения:
sum: 0
i: 1
На каждом шаге значения обновляются.
Вложенные циклы: таблица умножения
Код
for i := 1; i <= 3; i++ {
for j := 1; j <= 3; j++ {
product := i * j
fmt.Printf("%d*%d=%d ", i, j, product)
}
fmt.Println()
}
Трассировка выполнения
Итерация 1 внешнего цикла (i=1):
| Шаг | i | j | product | Вывод |
|---|---|---|---|---|
| 1 | 1 | 1 | 1 | 1*1=1 |
| 2 | 1 | 2 | 2 | 1*2=2 |
| 3 | 1 | 3 | 3 | 1*3=3 |
| 4 | 1 | — | — | Перевод строки |
Итерация 2 внешнего цикла (i=2):
| Шаг | i | j | product | Вывод |
|---|---|---|---|---|
| 5 | 2 | 1 | 2 | 2*1=2 |
| 6 | 2 | 2 | 4 | 2*2=4 |
| 7 | 2 | 3 | 6 | 2*3=6 |
| 8 | 2 | — | — | Перевод строки |
Итерация 3 внешнего цикла (i=3):
| Шаг | i | j | product | Вывод |
|---|---|---|---|---|
| 9 | 3 | 1 | 3 | 3*1=3 |
| 10 | 3 | 2 | 6 | 3*2=6 |
| 11 | 3 | 3 | 9 | 3*3=9 |
| 12 | 3 | — | — | Перевод строки |
Порядок выполнения вложенных циклов:
- Внешний цикл инициализирует
i=1 - Внутренний цикл выполняется полностью (j=1, 2, 3)
- Внешний цикл увеличивает
i=2 - Внутренний цикл снова выполняется полностью (j=1, 2, 3)
- И так далее
Практический пример: сумма первых N чисел
Задача
Найти сумму чисел от 1 до 10.
Решение через цикл
sum := 0
for i := 1; i <= 10; i++ {
sum += i
fmt.Printf("i=%d, sum=%d\n", i, sum)
}
fmt.Printf("Итого: %d\n", sum)
Вывод:
i=1, sum=1
i=2, sum=3
i=3, sum=6
i=4, sum=10
i=5, sum=15
i=6, sum=21
i=7, sum=28
i=8, sum=36
i=9, sum=45
i=10, sum=55
Итого: 55
Проверка правильности
Математическая формула: ( \text{sum} = \frac{n \times (n+1)}{2} )
Для ( n = 10 ): ( \frac{10 \times 11}{2} = \frac{110}{2} = 55 ) ✅
Примеры с условиями внутри циклов
Чётные числа от 1 до 10
fmt.Println("Чётные числа от 1 до 10:")
for i := 1; i <= 10; i++ {
if i%2 == 0 {
fmt.Printf("%d ", i)
}
}
Вывод: 2 4 6 8 10
Средняя оценка из случайных чисел
totalScore := 0
count := 5
fmt.Println("5 случайных оценок (1-100):")
for i := 1; i <= count; i++ {
score := rand.Intn(100) + 1
totalScore += score
fmt.Printf("Оценка %d: %d\n", i, score)
}
average := totalScore / count
fmt.Printf("Среднее: %d\n", average)
Пример вывода:
5 случайных оценок (1-100):
Оценка 1: 73
Оценка 2: 45
Оценка 3: 89
Оценка 4: 12
Оценка 5: 67
Среднее: 57
Рекомендации по отладке
1. Используйте дебаггер для сложных циклов
Особенно для вложенных циклов — ставьте точки останова и смотрите изменение переменных пошагово.
2. Проверяйте ожидаемый результат
Перед запуском подумайте: «Что должно получиться?». Например, сумма 1+2+…+10 = 55.
3. Печатайте промежуточные значения
for i := 1; i <= 3; i++ {
fmt.Printf("Итерация %d, i=%d\n", i, i)
}
4. Изучайте паттерны
- Счётчик вверх:
i++с условиемi <= N - Счётчик вниз:
i--с условиемi >= 1 - Шаг больше 1:
i += 2для чётных/нечётных
Ключевые моменты
- Порядок: init (1 раз) → condition → body → post → condition → …
- Init выполняется один раз перед началом цикла
- Condition проверяется перед каждой итерацией
- Post выполняется после каждой итерации
- Область видимости: счётчик из init виден только в цикле
- Вложенные циклы: внутренний полностью завершается перед следующей итерацией внешнего
- Дебаггер: Step Over (F10) для пошагового выполнения
- Проверка: считайте ожидаемый результат до запуска
- Вариации: можно опускать init/post (использовать внешние переменные)
- Практика: решайте задачи пошагово с дебаггером для понимания