Условные операторы в Go
TL;DR
Условные операторы в Go позволяют менять поток выполнения программы в зависимости от значений. Используйте if для простых проверок, if — else и цепочки else if для разветвлений, а switch для сопоставления с набором значений или типов. Для больших наборов случаев рассмотрите map или полиморфизм.
Введение
Условные операторы (conditional statements) позволяют выполнять код в зависимости от логического выражения (true/false). В Go доступны привычные формы: if, if…else, if…else if…else и switch. Здесь мы разберём синтаксис, примеры, шаблоны замены и рекомендации по выбору подхода.
Важно: в Go нет неявных преобразований типов для булевых выражений — условие должно давать bool.
Базовый if
Оператор if выполняет блок кода, если условие истинно. Синтаксис:
if condition {
// Блок кода
}Пример вывода “Pass”, если marks больше 50:
marks := 60
if marks > 50 {
fmt.Println("Pass")
}Инициализация переменной непосредственно в if:
if marks := 60; marks > 50 {
fmt.Println("Pass")
}Пояснение: выражение после точки с запятой — короткое объявление; область видимости переменной ограничена блоком if/else.
Логические операторы
Go поддерживает && (AND), || (OR) и ! (NOT).
- && возвращает true, если обе стороны true.
- || возвращает true, если хотя бы одна сторона true.
- ! инвертирует булевое значение.
Примеры:
sunny := true
noClass := true
if sunny && noClass {
fmt.Println("Go to the beach")
}today := "Sunday"
if today == "Sunday" || today == "Saturday" {
fmt.Println("Sleep in")
}marksAvailable := true
if !marksAvailable {
fmt.Println("No marks available!")
}if…else
Если нужно два пути выполнения — используйте if…else:
if condition {
// если истина
} else {
// если ложно
}Пример:
marks := 60
if marks > 50 {
fmt.Println("Pass")
} else {
fmt.Println("Fail")
}if…else if…else
Для нескольких ветвей используйте цепочку else if:
if condition1 {
// если condition1
} else if condition2 {
// если condition2
} else {
// ни одно условие не выполнено
}Пример с отличием (distinction):
marks := 60
if marks > 80 {
fmt.Println("Passed with distinction")
} else if marks > 50 {
fmt.Println("Pass")
} else {
fmt.Println("Fail")
}switch
Switch удобен, когда нужно сопоставить выражение с множеством значений. В Go по умолчанию блоки не переливаются (no implicit fallthrough).
switch expression {
case expr1:
// код
case expr2:
// код
default:
// код если нет совпадений
}Пример: вывод дела на каждый день недели.
package main
import (
"fmt"
"time"
)
func main() {
today := time.Now().Weekday()
switch today {
case 0:
fmt.Println("Relax.")
case 1:
fmt.Println("Clean the house.")
case 2:
fmt.Println("Visit the dentist.")
case 3:
fmt.Println("Weed the garden.")
case 4:
fmt.Println("Send gifts")
case 5:
fmt.Println("Do laundry.")
case 6:
fmt.Println("Write a blog post.")
default:
fmt.Println("No task scheduled.")
}
}Примечание: в реальном коде time.Weekday() возвращает тип time.Weekday с именованными константами (Sunday, Monday…). Пример выше использует значения как в исходной статье — имейте в виду соответствие типов.
Типовые расширения switch
- Несколько значений в case: case 1, 2, 3:
- switch без выражения — удобен для замены цепочек if…else if.
- type switch — проверка типа интерфейса:
switch v := x.(type) {
case int:
// v имеет тип int
case string:
// v имеет тип string
default:
// другой тип
}Когда использовать if, switch, map или полиморфизм
Решение зависит от количества ветвей, характера выражений и потребностей в расширяемости.
- if: логические выражения, диапазоны, проверки на nil, краткие и понятные условия.
- switch: много альтернатив по точным значениям, компактность и читаемость.
- map[Key]func: когда нужно сопоставить большое количество ключей с действиями и быстро добавлять/удалять кейсы.
- Полиморфизм/интерфейсы: когда поведение зависит от типа объекта и требуется расширяемость.
Mermaid диаграмма для принятия решения:
flowchart TD
A[Есть условие?] --> B{Тип условия}
B -->|Логическое/диапазон| C[if]
B -->|Сравнение с множеством статичных значений| D[switch]
B -->|Много уникальных ключей| E[map -> func]
B -->|Зависит от типа объекта| F[интерфейс/полиморфизм]Примеры альтернатив и когда не подходят
- Много похожих case в switch делает код громоздким — лучше map с функциями.
- Сложные вложенные if ухудшают читаемость — реорганизуйте в функции с понятными именами.
- Если логика зависит от типа, type switch удобнее, но если поведение сложно — интерфейсы лучше.
Шаблон выбора (мини-методология)
- Определите характер условий: логические, дискретные значения или типы.
- Если кратко и понятно — if/else.
- Если множество дискретных значений — switch.
- Если набор значений большой и изменяется — map действий.
- Если поведение зависит от типа и требуется расширяемость — интерфейсы.
Чек-лист для разработчика
- Понятно ли условие при первом прочтении?
- Нет ли дублирования кода в ветках?
- Можно ли вынести ветвь в отдельную функцию с именем, описывающим поведение?
- Не слишком ли много case в switch — стоит ли заменить на map?
Критерии приёмки (тесты)
- Для if: проверка true/false и граничных значений.
- Для switch: все ожидаемые case покрыты; default — обрабатывает неожиданные значения.
- Для map->func: проверка поведения для существующих ключей и обработка отсутствующих ключей.
Пример тест-кейсов для оценки задачных примеров:
- marks = 85 => Passed with distinction
- marks = 60 => Pass
- marks = 40 => Fail
- День недели = значение вне диапазона => default ответ
Подсказки и «шпаргалка» (cheat sheet)
- Инициализация в if: if v := f(); v > 0 { … }
- Нет неявного fallthrough в switch; используйте fallthrough явно.
- switch без выражения эквивалентен цепочке if…else if.
- Проверка типов: switch v := x.(type) { … }
Короткий глоссарий
- if: оператор ветвления для булевых выражений.
- switch: оператор сопоставления значения с набором кейсов.
- fallthrough: ключевое слово для явного перехода к следующему case.
- type switch: переключение по реальному типу значения интерфейсного типа.
Контрпримеры и ограничения
- Если вам нужно выполнять набор действий в порядке при совпадении нескольких условий, обычный switch может не подойти из-за отсутствия автоматического fallthrough. В таких случаях лучше явно вызывать последовательность функций.
- Если условие становится слишком длинным — выносите проверку в функцию с говорящим именем.
Итог
Условные операторы — базовый инструмент управления потоком в Go. Выбирайте if для логики и диапазонов, switch для набора дискретных значений, map или интерфейсы для масштабируемости. Чистая структура, читаемость и покрытие тестами важнее хитроумных конструкций.
Важно: придерживайтесь кратких функций и понятных имен — это упростит поддержку и тестирование.
Сводка:
- Используйте if для простых проверок и инициализации значений.
- Используйте switch для многовариантного выбора.
- Рассмотрите map или полиморфизм для больших и изменчивых наборов кейсов.