Перейти к содержимому
Теория · Операторы · урок 5 из 9

Сравнения и логика

До сих пор калькулятор Go отвечал числами. Но программе постоянно нужны и другие ответы — «да» или «нет»: совершеннолетний ли пользователь, попадает ли число в диапазон. Такой ответ даёт сравнение, и его результат имеет тип bool:

GO
package main

import "fmt"

func main() {
    age := 20
    adult := age >= 18
    teen := age >= 13 && age <= 19
    fmt.Println(adult, teen) // true false
}

Давайте разберём пример по строкам:

  1. age := 20 объявляет возраст.
  2. adult := age >= 18 — для 20 это верно, поэтому adult равна true.
  3. teen := age >= 13 && age <= 19 — age >= 13 верно, но 20 <= 19 неверно. Оператор && требует, чтобы были верны обе части, поэтому teen равна false.
  4. fmt.Println(adult, teen) печатает true false.

Шесть операторов сравнения

В Go шесть операторов сравнения:

  • == — равно;
  • != — не равно;
  • < — меньше;
  • <= — меньше или равно;
  • > — больше;
  • >= — больше или равно.

Равенство проверяет двойной знак ==, а одиночный = присваивает значение. Сравнивать можно только значения одного типа: для n типа int выражение n < 2.5 не скомпилируется.

Логические операторы

Логические операторы работают со значениями типа bool и собирают из нескольких ответов «да/нет» один. Их три.

&& — И

Выражение a && b даёт true, только когда верны оба операнда. Если хотя бы один из них false, результат — false.

Его берут, когда должны выполниться все условия сразу. Типичный пример — попадание в диапазон: age >= 13 && age <= 19.

|| — ИЛИ

Выражение a || b даёт true, когда верен хотя бы один операнд. Результат false получается, только когда оба операнда false.

Его берут, когда подходит любой из вариантов: day == 6 || day == 7 верно и для субботы, и для воскресенья.

! — НЕ

Оператор ! стоит перед одним операндом и меняет true на false и обратно: !adult верно, когда adult равна false.

У ! есть ловушка: он относится только к ближайшему операнду. Чтобы отрицать сравнение, возьмите его в скобки: !(age >= 18). Без скобок !age >= 18 не скомпилируется.

Число вместо bool логические операторы не принимают. Для x типа int выражение !x не скомпилируется.

Порядок вычисления

В одном выражении операторы выполняются в таком порядке:

  1. арифметика: n%2 == 0 значит (n%2) == 0;
  2. сравнения;
  3. &&;
  4. ||.

&& группирует операнды раньше ||, как умножение раньше сложения: a || b && c значит a || (b && c). Скобки делают такой порядок заметным, и лишними они не бывают.

Короткое замыкание

Представьте охранника на входе в клуб. Он пускает гостя, если у того есть билет и ему исполнилось 18. Если билета нет, про возраст охранник уже не спрашивает: ответ всё равно «нет».

&& и || ведут себя так же. Сначала они вычисляют левый операнд. Если по нему ответ уже ясен, правый они не вычисляют вовсе:

  • && пропускает правый операнд, когда левый — false;
  • || пропускает правый операнд, когда левый — true.

Такое правило называют коротким замыканием:

GO
package main

import "fmt"

func isEven(n int) bool {
    fmt.Print("isEven ")
    return n%2 == 0
}

func main() {
    fmt.Println(isEven(3) && isEven(4)) // isEven false
    fmt.Println(isEven(4) || isEven(3)) // isEven true
}

fmt.Print печатает без перевода строки, поэтому слово и результат стоят на одной строке. Давайте разберём обе строки main:

  1. isEven(3) && isEven(4) печатает isEven false: isEven(3) вернула false, и Go не вызвал isEven(4).
  2. isEven(4) || isEven(3) печатает isEven true: isEven(4) вернула true, и Go не вызвал isEven(3).

Короткое замыкание позволяет правому операнду опираться на левый: в d != 0 && n/d > 2 деления на ноль не будет.

Охранник может начать с любого вопроса, а Go — нет: он всегда вычисляет сначала левый операнд. Поэтому порядок операндов важен. Короткое замыкание — частый вопрос на собеседовании: показывают выражение с вызовом функции справа от && и спрашивают, что напечатает программа.

Частая ошибка

Попадание в диапазон записывают так же, как в математике:

GO
x := 15
fmt.Println(0 < x < 10) // ✗
TEXT
invalid operation: 0 < x < 10 (mismatched types untyped bool and untyped int)

Программа не компилируется. Go читает выражение как (0 < x) < 10: слева получается bool, а сравнивать bool с числом нельзя. Диапазон проверяют двумя сравнениями: 0 < x && x < 10.

Главное

  • Сравнение даёт bool; равенство проверяет ==, а = присваивает.
  • && верно, когда верны оба операнда, || — когда верен хотя бы один; && группирует раньше ||.
  • Правый операнд && не вычисляется при левом false, а правый операнд || — при левом true.
  • Диапазон проверяют двумя сравнениями: 0 < x && x < 10.

Подпишись, чтобы пройти курс

Курс бесплатный. Войди через Telegram и подпишись на канал — откроются все уроки.

Войти другим способом