---
title: "Условия: if и else"
description: "Условия в Go: if, else и else if, логические операторы, переменная в заголовке if и её область видимости, ранние возвраты вместо вложенности."
course: "Go с нуля: базовый синтаксис и конструкции"
url: "https://golangmaster.ru/courses/go-basics/lessons/11-usloviya-if/"
published: "2026-09-19"
updated: "2026-09-28"
minutes: 15
---

# Условия: if и else

*Курс «Go с нуля: базовый синтаксис и конструкции», урок 11 из 25. ~15 минут. Обновлено 28.09.2026. Источник: https://golangmaster.ru/courses/go-basics/lessons/11-usloviya-if/*

До этого урока каждая наша программа шла сверху вниз и делала всё, что написано, без вопросов. Настоящие программы стоят на развилках: пароль подошёл или нет, хватает ли денег на карте, пустили ли в фильм. Условия в Go расставляют эти развилки: оператор if выполняет блок кода только когда условие истинно, а else держит наготове запасной путь. Разберём if, else и else if, логические операторы в условиях, переменную, объявленную прямо в заголовке if, и ошибки, на которых спотыкается почти каждый новичок.

### Условия в go: как устроен оператор if

Развилка начинается с вопроса, на который есть ровно два ответа — да или нет. Такой вопрос записывается булевым выражением: строить их мы научились в уроке про [bool и логику](/courses/go-basics/lessons/07-bool-i-logika/) — сравнения `age >= 18`, `password == "secret"`, `balance <= 0` дают true или false. Оператор if берёт выражение и выполняет свой блок только при true; при false блок молча пропускается, и программа едет дальше по прямой.

Запись лаконичная: `if age >= 18 { fmt.Println("проходите") }`. Круглые скобки вокруг условия в Go не пишут: компилятор их стерпит, но gofmt, стандартный форматировщик, молча их удалит, и весь идиоматичный код живёт без них. Зато фигурные скобки обязательны всегда, даже если в блоке одна строка. И деталь на будущее: отступы — только для людей, компилятор смотрит исключительно на скобки.

### Песочница: первая развилка

Запустите: 14 > 20 ложно, сработал else. Поменяйте temp на 25 — теперь условие истинно и печатается первая строка. Затем допишите после else ещё один независимый if: `if temp < 0 { fmt.Println("лёд на дороге") }` и подберите значение temp, при котором напечатаются и подсказка про куртку, и предупреждение про лёд.

```go
package main

import "fmt"

func main() {
        temp := 14
        if temp > 20 {
                fmt.Println("тепло, можно без куртки")
        } else {
                fmt.Println("прихватите куртку")
        }
        fmt.Println("проверка закончена")
}
```

### If else go: развилка на две дороги

Пара, которую ищут по запросу «if else go», — это две дороги, из которых выполняется ровно одна. Ветка else не имеет собственного условия: она срабатывает во всех остальных случаях, когда проверка if дала false. Гарантия «что-то одно, но что-то обязательно» — главное свойство развилки: если в блоке else увеличивать счётчик неудачных попыток, он не задвоится ни при каком раскладе.

У else есть синтаксическая странность, о которую спотыкается каждый второй: слово else обязано стоять на той же строке, где закрывающая скобка if. Перенесёте его на следующую строку — получите ошибку про неожиданный else, причём винить захочется строку с else, а виновата строка выше: Go сам вставляет точку с запятой в конец строки после `}` и отрезает else от его if. Песочница ругается точно так же. Правило короткое: `} else {` — одна строка.

### Проверьте себя: заголовок ветвления

**Вопрос:** Переменная x уже объявлена. Как правильно записать заголовок ветвления в Go?

- if (x > 5) { ... } — условие берут в круглые скобки
- ✅ if x > 5 { ... } — без круглых скобок, тело в фигурных
- if x > 5: ... — тело блока задаётся отступом
- if { x > 5 } — и условие, и тело в фигурных скобках

Условие пишется без круглых скобок: gofmt удаляет их из кода, так что идиоматичный вариант один. Фигурные скобки обязательны даже для одной команды — телом ветвления в Go может быть только блок. Отступ для компилятора ничего не значит: это правило из Python, а не из Go.

### Else if: цепочка проверок

Двух дорог часто мало: оценка превращается в пять слов, температура — в диапазон «жарко, тепло, прохладно, холодно». Для лестницы проверок есть else if: условия перебираются сверху вниз, и первая же истинная ветка выполняется, а все нижние пропускаются — даже если их условия тоже истинны. Финальный else без условия необязателен: он ловит «всё остальное» и спасает, когда ни одна проверка не выстрелила.

Отсюда правило, которое экономит часы отладки: от самого строгого условия — к самому мягкому. Поставьте проверку на 70 выше проверки на 90, и отличник с результатом 95 навсегда станет «хорошим»: до второй ветки очередь не доходит. В песочнице ниже это видно без слов.

### Песочница: ведомость с оценками

Запустите: 74 попадает в ветку «хорошо», до остальных проверок дело не доходит. Прогоните score = 95, 50 и 3. А теперь поменяйте ветки местами — поставьте проверку score >= 70 первой — и запустите с score = 95: отличник превратится в «хорошо», хотя вторая ветка тоже истинна. Первая победившая проверка обрывает цепочку.

```go
package main

import "fmt"

func main() {
        score := 74
        if score >= 90 {
                fmt.Println("отлично")
        } else if score >= 70 {
                fmt.Println("хорошо")
        } else if score >= 50 {
                fmt.Println("удовлетворительно")
        } else {
                fmt.Println("не сдал")
        }
}
```

### Логические операторы в условиях: и, или, не

Одно сравнение редко решает судьбу ветки: возраст подходит «и» билет куплен, день выходной «или» праздник, доступ запрещён, когда «не» админ. Условия собирают из булевой арифметики, которую мы разбирали в уроке про bool и логику: `&&` требует истинности обоих операндов, `||` — хотя бы одного, `!` переворачивает значение. Диапазон «от 18 до 35» записывается парой сравнений через &&: `age >= 18 && age <= 35` — арифметическую запись `18 <= age <= 35` Go не примет, каждое сравнение надо проговаривать целиком.

Приоритеты операторов из урока про [операторы и выражения](/courses/go-basics/lessons/08-operatory/) работают и здесь: && связывает крепче ||, поэтому `a || b && c` читается как `a || (b && c)`. Сомневаетесь — ставьте скобки: внутри условия они разрешены, запрет касается только внешних скобок вокруг всего выражения. Плюс сокращённые вычисления: если левая часть && уже ложна, правую Go даже не вычисляет. На этом строятся безопасные проверки вроде `len(parts) > 0 && parts[0] == "Аня"`: у пустого среза левая половина ложна, и до обращения parts[0] дело не доходит.

### Таблица истинности для условий

| a | b | a && b | a || b | !a |
| --- | --- | --- | --- | --- |
| true | true | true | true | false |
| true | false | false | true | false |
| false | true | false | true | true |
| false | false | false | false | true |

### Что выведет код?

```go
package main

import "fmt"

func main() {
        age := 16
        ticket := false
        if age >= 12 && ticket {
                fmt.Println("проход в зал")
        }
        if age < 12 || ticket {
                fmt.Println("льгота")
        }
        if !(age < 12) {
                fmt.Println("взрослый билет")
        }
}
```

**Что выведет программа?**

- ✅ взрослый билет
- проход в зал и льгота
- проход в зал
- льгота и взрослый билет

age равно 16, ticket — false. Первое условие: 16 >= 12 && false — ложно, && требует обоих операндов. Второе: false || false — тоже ложно, || требует хотя бы одного истинного операнда, а здесь их нет. Третье условие спасает отрицание: !(16 < 12) — это !false. Обе ловушки крутятся вокруг ticket: одно false в && обнуляет пару, а в || без единого true пара пуста.

### Переменная в if: инициализирующий оператор и область видимости

В уроке про [ввод данных](/courses/go-basics/lessons/10-scan-vvod/) мы видели проверку ошибки `if err != nil`. На практике она почти всегда выглядит иначе: `if n, err := strconv.Atoi(s); err != nil`. Между if и условием через точку с запятой можно вписать инициализирующий оператор — обычно короткое объявление `:=`. Он выполняется до проверки условия, а объявленные переменные живут ровно внутри конструкции: доступны в блоке if, в ветках else if и else — и исчезают сразу после закрывающей скобки.

Это не украшение, а способ держать переменные при их деле. n и err нужны только чтобы решить судьбу числа, — значит, им и место внутри if. Попытка напечатать n после конструкции закончится ошибкой undefined: n — за пределами развилки такой переменной нет, и это хорошо: меньше шансов случайно взять устаревшее значение. Оператор работает и без ошибок в придачу: `if t := temp - 5; t >= 25 { ... }`. А если значение нужно в нескольких местах ниже по коду, объявляйте его обычным `:=` — тонкости обоих способов разбирались в уроке про [переменные и константы](/courses/go-basics/lessons/04-peremennye-konstanty/).

### Песочница: переменная внутри развилки

Запустите: из двух слов собрался разбор «имя и возраст». Замените input на "Аня" — сработает else со счётом слов. А теперь допишите после конструкции строку `fmt.Println(parts[0])` и запустите: песочница откажется так же, как настоящий компилятор, — parts не определена за пределами if. Уберите лишнюю строку обратно.

```go
package main

import (
        "fmt"
        "strings"
)

func main() {
        input := "Аня 25"
        if parts := strings.Fields(input); len(parts) == 2 {
                fmt.Println("имя и возраст:", parts[0], parts[1])
        } else {
                fmt.Println("ожидали два слова, а было", len(parts))
        }
}
```

> **Совет: сужайте область видимости.** Чем короче живёт переменная, тем меньше мест, где её можно случайно испортить или забыть, зачем она. Значение нужно для одного решения — объявляйте его в if; нужно в трёх местах ниже — обычным := на уровне функции. Я почти никогда не оставляю n и err из разбора ввода жить дальше проверки ошибки: пока переменная заперта в if, её актуальность гарантирована всей конструкцией.

### Типичные ошибки: скобки, лишний else и не-булево условие

Три ошибки встречаются так часто, что их стоит назвать поимённо.

Первая — лишний else. Если ветка if завершает работу — печатает вердикт или делает return, — else не нужен: после развилки всё равно ничего не исполняется, а каждая вложенная else добавляет отступ, то есть прямую трату внимания читателя.

Вторая — не-булево условие. В Go нет «истинных чисел»: `if count` при целом count не скомпилируется, ноль не считается ложью, пустая строка — тем более. Проверяют явно: `if count > 0`. Заодно это страхует от классической опечатки: `if x = 5` не пройдёт, потому что присваивание не возвращает значения, — компилятор ловит то, что в C часто становится невидимым багом.

Третья вам уже знакома — else с новой строки: автоматическая точка с запятой после `}` отрезает ветку от if. Итого три коротких правила: без скобок вокруг условия, без else после завершающей ветки, `} else {` на одной строке.

### Ранний выход вместо else

```go
package main

import "fmt"

func main() {
        password := "qwerty"
        if password != "secret" {
                fmt.Println("доступ запрещён")
                return
        }
        fmt.Println("добро пожаловать")
}
```

return завершает main: если пароль не подошёл, до строки с приветствием дело не доходит. Проверка плохого случая стоит первой и убирается с дороги, а главный путь — печатать приветствие — остаётся прижатым к левому краю без единого else. Пока мы пишем только main, эффект скромный, но когда дойдём до функций, этот приём вырастет в guard clause — «условие-страж», стандартный способ держать вложенность на глубине одного if.

### Ранние возвраты против вложенности

Когда проверок несколько и каждая зависит от предыдущей, код легко уезжает вправо: if внутри if внутри else — три отступа, и уже непонятно, какой if чьё условие охраняет. Лекарство то же — ранний выход: плохие случаи проверяются первыми и сразу завершают работу, основной путь остаётся прямым. Внутри main для этого служит return, как в примере выше; в будущих функциях он же вернёт значение вызывающему коду.

Моё правило простое: если тело if заканчивается return, else не нужен, — и я рад, что линтеры в большинстве команд проверяют это автоматически. Спорить можно об одном: в короткой паре «если/иначе» с двумя симметричными действиями else читается нормально, вырывать его насильно не стоит.

И последнее: если одна переменная сравнивается с пачкой значений, длинная лестница else if — не лучший выбор. Для этого в Go есть switch — тема следующего урока про [множественный выбор](/courses/go-basics/lessons/12-switch/).

### Вставьте ключевые слова

Соберите цепочку из трёх веток: при temp 8 программа должна напечатать «холодно». Три пропуска — по одному на каждое ключевое слово цепочки.

```go
temp := 8
___ temp > 25 {
        fmt.Println("жарко")
} ___ temp > 15 {
        fmt.Println("тепло")
} ___ {
        fmt.Println("холодно")
}
```

Подсказка: Первое слово открывает проверку, второе добавляет к цепочке следующее условие, третье ловит всё остальное.

Правильные ответы в пропусках: `if`, `else if`, `else`

### Соберите программу с переменной в if

Соберите программу: из temp вычитается пять, и переменная t, объявленная в заголовке if, решает, что печатать. Правильная программа выводит «жарко: 26».

Правильный порядок строк:

1. `package main`
2. `import "fmt"`
3. `func main() {`
4. `temp := 31`
5. `if t := temp - 5; t >= 25 {`
6. `fmt.Println("жарко:", t)`
7. `} else {`
8. `fmt.Println("нормально:", t)`
9. `}`
10. `}`

### Карточки: условия и ветвление

- **Как выглядит заголовок if в Go?** — if условие { ... }: без круглых скобок вокруг условия, фигурные скобки обязательны даже для одной команды, а условие должно иметь тип bool.
- **Где должен стоять else?** — На той же строке, что закрывающая скобка if: } else {. Иначе Go вставит точку с запятой после скобки и пожалуется на неожиданный else.
- **Что делает else if?** — Продолжает цепочку проверок: условия перебираются сверху вниз, первая истинная ветка выполняется, остальные пропускаются. Финальный else без условия — необязательная страховка.
- **Что такое инициализирующий оператор в if?** — Объявление между if и условием через точку с запятой: if n, err := strconv.Atoi(s); err != nil. Переменные видны во всей конструкции if/else и умирают после неё.
- **Когда else не нужен?** — Когда тело if завершает работу: печатает вердикт или делает return. Ранний выход держит основной путь без лишних отступов — это guard clause, «условие-страж».
- **Почему if count при целом count не работает?** — Условие if обязано быть bool: в Go нет «истинных чисел», ноль не считается ложью. Пишут явное сравнение: if count > 0. Бонус: опечатка = вместо == в условии не пройдёт.

## Коротко: что запомнить

- if выполняет блок только при истинном условии; условие — bool, без круглых скобок, фигурные скобки обязательны.
- else — запасная ветка без своего условия; слово else ставится на строку закрывающей скобки: } else {.
- else if строит цепочку: первая истинная проверка побеждает, поэтому условия идут от строгого к мягкому.
- В условиях && требует истинности обоих операндов, || — хотя бы одного, ! переворачивает значение.
- Инициализирующий оператор if n, err := f(); err != nil объявляет переменные только для конструкции if.
- Переменные из if-инициализации не видны после if — это защита от лишних зависимостей, а не недоработка.
- Ранний возврат вместо else: проверь плохой случай и уходи, основной путь остаётся без вложенности.

## Домашнее задание

Соберите кассу кинотеатра: price := 250 и age := 15. Правила: возраст до 12 включительно или от 65 — половина цены (price/2); от 13 до 18 — цена без пятой части (price - price/5); остальным — полная. Уложитесь в одну цепочку if/else if/else с операторами || и && и печатайте «цена: N». Проверьте три возраста: 15 (ожидайте 200), 70 (125) и 30 (250). Затем перепишите решение с ранними возвратами: каждый льготный случай печатает цену и сразу делает return — else в программе остаться не должно.

## Вопросы и ответы по уроку

### Обязательны ли фигурные скобки, если в ветке одна команда?

Да, в Go не бывает if без блока: тело ветвления — всегда фигурные скобки, отступ их не заменяет. Это осознанное решение языка: одна из самых дорогих ошибок в истории — баг goto fail в iOS 2014 года — случилась в коде без скобок, где лишняя строка оказалась снаружи проверки и выполнялась всегда.

### Чем else if отличается от вложенного if в else?

Только формой записи: else if — это if внутри else, прижатый в одну строку, чтобы цепочка читалась сверху вниз без лесенки отступов. Семантика одинаковая, но длинные вложенные else уезжают вправо и теряют читателей, поэтому цепочка — стандартный вид.

### Можно ли объявить переменную в if через var, а не :=?

Можно: инициализирующий оператор — это обычный оператор, и var там допустим. Но := короче и не требует заранее придуманного типа, поэтому в заголовках if пишут почти всегда его. Правило одно для обоих вариантов: переменные видны только внутри всей конструкции if/else и не живут после неё.
