В ситуациях, когда ход работы программы должен меняться в зависимости от условия, применяют операторы ветвления, или, как их ещё называют, условные операторы. В языке Go есть как стандартные условные операторы, так и специфичные для языка.
Для начала вспомним операторы сравнения (переменных одного типа):
- >— больше;
- <— меньше;
- >=— больше или равно;
- <=— меньше или равно;
- == — равно;
- !=— не равно.
А также логические операторы:
- &&— логическое И;
- ||— логическое ИЛИ;
- !— логическое НЕ.
Теперь рассмотрим конструкции if — else и switch — case. Первая конструкция — стандартный условный оператор. Вторая — более специфичная, встречается не во всех языках программирования и применяется реже.
Условие if — else
if a == 1 {
    // сценарий, если условие if выполнено
} else if a == 2 {
    // сценарий, если условие else if выполнено
} else {
    // сценарий, если условие else if не выполнено
} Это простой пример условной конструкции. Она может состоять только из одного оператора if — тогда блок кода сработает, если условие верно, а если неверно, то ничего не произойдёт.
Опционально можно добавить оператор else. За ним будет следовать блок кода, который выполнится, если исходное условие неверно.
И наконец, если нужно обработать несколько различных условий, используют оператор else if. В код можно добавить много else if, но это не самый «читабельный» вариант — в подобных случаях лучше использовать case, о котором расскажем ниже.
Приведём примеры операторов с различными вариантами условий:
// логическое НЕ
// возвращается одна переменная типа bool
a := false
if !a {} 
 
// логическое И
var a, b int
if a == 1 && b == 2 {}
 
// исключающее ИЛИ (XOR)
var a, b bool
if (a || b) && !(a && b) {}Общие правила для условных операторов:
- Обязательно использовать фигурные скобки { }, чтобы обозначить область видимости оператора.
- Необязательно заключать основное условие в круглые скобки ( ), но с ними удобнее читать код.
- Можно добавлять круглые скобки ( ), чтобы группировать части условия.
В#Go применяется «ленивая» проверка условий: она идёт слева направо до первого false и прекращается, потому что проверять дальше нет смысла. Пример «ленивой» проверки:
a, b := 1, 0
 
if a == 1 || b == 2 {
    fmt.Println("Hello")
} В данном примере выполняется левое условие, поэтому проверки (или выполнения) правой части не последует. Пример будет более показателен, если для правой части условия использовать функциональный литерал (подробнее расскажем в теме «Функции»), который будет просто изменять значение переменной b.
a, b := 1, 0
 
incB := func() bool {
    b = b + 1
    return true
}
 
if a == 1 || incB() {
    fmt.Println("Hello")
}
 
fmt.Println(a, b)Из-за «ленивой» проверки условий функция incB не выполнится — её значение не изменится, то есть функция не изменит значение переменной, потому что выполнение кода прервётся.
Оператор if может состоять из двух компонент: инициализации и основного условия. Такая техника позволяет объявлять локальную переменную, которую используют только в рамках области видимости if. Это может пригодиться, например, когда нужно преобразовать данные для сравнения.
a := 0.10000001 // float64
// инициализация и основное условие
if b := float32(a); b > float32(0.1) {
    fmt.Println("Var a is GT float32(0.1)")
} 
Условие в данном примере может перестать выполняться, если добавить ещё один ноль: 0.100000001. Тип float32 обеспечивает точность в восемь десятичных чисел, в то время как точность float64 составляет около 15 чисел.
Условие switch — case
var a int
 
switch a {
case 1:
    fmt.Println("1")
case 2:
    fmt.Println("2")
case 3, 4:
    fmt.Println("3 or 4")
default:
    fmt.Println("Default case")
} Конструкция switch — case позволяет избежать дублирования else if. Проверка условий идёт сверху вниз и слева направо, поэтому в примере выше условия будут проверяться в таком порядке: 1, 2, 3, 4.
Наличие блока default необязательно — его можно опустить, если не требуется описывать «стандартное» поведение. Этот блок выполнится, если ни одно из условий не отработало.
Основное условие switch может быть не задано явно:
var a int
 
switch {
case a == 100:
    fmt.Println("EQ 100")
case a > 0:
    fmt.Println("GT 0 AND NEQ 100")
case a < 0:
    fmt.Println("LT 0 AND NEQ 100")
} В этом примере важен порядок условий case: если переместить a == 100 в конец, то a > 0 всегда будет срабатывать первым для положительных чисел. Такая форма оператора аналогична множественному else if.
Внутри switch можно объявить локальную переменную, доступную только в пределах области видимости оператора:
a := 6
switch b := a % 5; {
case b == 0:
    fmt.Println("Кратно 5")
default:
    fmt.Printf("Остаток от деления на 5: %d", b)
} Чтобы досрочно прервать выполнение case, используют ключевое слово break. Это бывает полезно, когда внутри case есть условные конструкции. В Go нет необходимости явно указывать break в конце каждого case, так как следующий блок case автоматически не выполнится при совпадении условия.
Когда нужно всё-таки выполнить следующий блок, используют ключевое слово fallthrough. Если указать его в конце блока кода, то после него будет выполнен блок в следующем case или default.
a := -100
switch {
case a > 0:
    if a % 2 == 0 {
        break
    }
    fmt.Println("Odd positive value received")
case a < 0:
    fmt.Println("Negative value received")
    fallthrough
default:
    fmt.Println("Default value handling")
} У ключевого слова fallthrough есть особенности:
- его можно использовать только в последней строке case, иначе будет ошибка компиляции;
- оно игнорирует условие следующего по порядку case.
📂 Go | Последнее изменение: 24.08.2024 10:35