Сравнения и логика
До сих пор калькулятор Go отвечал числами. Но программе постоянно нужны и другие ответы — «да» или «нет»: совершеннолетний ли пользователь, попадает ли число в диапазон. Такой ответ даёт сравнение, и его результат имеет тип bool:
package main
import "fmt"
func main() {
age := 20
adult := age >= 18
teen := age >= 13 && age <= 19
fmt.Println(adult, teen) // true false
}Давайте разберём пример по строкам:
age := 20объявляет возраст.adult := age >= 18— для20это верно, поэтомуadultравнаtrue.teen := age >= 13 && age <= 19—age >= 13верно, но20 <= 19неверно. Оператор&&требует, чтобы были верны обе части, поэтомуteenравнаfalse.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 не скомпилируется.
Порядок вычисления
В одном выражении операторы выполняются в таком порядке:
- арифметика:
n%2 == 0значит(n%2) == 0; - сравнения;
&&;||.
&& группирует операнды раньше ||, как умножение раньше сложения: a || b && c значит a || (b && c). Скобки делают такой порядок заметным, и лишними они не бывают.
Короткое замыкание
Представьте охранника на входе в клуб. Он пускает гостя, если у того есть билет и ему исполнилось 18. Если билета нет, про возраст охранник уже не спрашивает: ответ всё равно «нет».
&& и || ведут себя так же. Сначала они вычисляют левый операнд. Если по нему ответ уже ясен, правый они не вычисляют вовсе:
&&пропускает правый операнд, когда левый —false;||пропускает правый операнд, когда левый —true.
Такое правило называют коротким замыканием:
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:
isEven(3) && isEven(4)печатаетisEven false:isEven(3)вернулаfalse, и Go не вызвалisEven(4).isEven(4) || isEven(3)печатаетisEven true:isEven(4)вернулаtrue, и Go не вызвалisEven(3).
Короткое замыкание позволяет правому операнду опираться на левый: в d != 0 && n/d > 2 деления на ноль не будет.
Охранник может начать с любого вопроса, а Go — нет: он всегда вычисляет сначала левый операнд. Поэтому порядок операндов важен. Короткое замыкание — частый вопрос на собеседовании: показывают выражение с вызовом функции справа от && и спрашивают, что напечатает программа.
Частая ошибка
Попадание в диапазон записывают так же, как в математике:
x := 15
fmt.Println(0 < x < 10) // ✗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 и подпишись на канал — откроются все уроки.