Булевы значения, nil и сравнения

Логика программы строится на ответах «да/нет». В Ruby за это отвечают true и false, а особняком стоит nil — «ничего», которое нужно уметь приручать.
Суть: в Ruby «ложными» считаются только false и nil; всё остальное (включая ноль и пустую строку) — «истина». Это правило определяет поведение всех условий.

Многие языки считают ноль или пустую строку «ложью». Ruby — нет. Здесь действует простое и строгое правило: ложны ровно два значения — false и nil. Число 0, пустая строка "", пустой массив [] — всё это в условии истинно. Запомнить это правило важнее, чем кажется: на нём спотыкаются программисты, пришедшие из JavaScript или Python.

puts "0 истинно" if 0          # напечатает — 0 это истина
puts "пусто истинно" if ""     # напечатает — пустая строка истина
puts "nil ложно" unless nil    # напечатает — nil ложь
puts "false ложно" unless false

Разбор: операторы сравнения

Сравнения возвращают true или false. Базовый набор знаком: == (равно), != (не равно), <, >, <=, >=. Особый оператор «космический корабль» <=> возвращает -1, 0 или 1 и используется для сортировки.

puts (3 <=> 5)   # => -1 (меньше)
puts (5 <=> 5)   # => 0  (равно)
puts (8 <=> 5)   # => 1  (больше)
puts 5.between?(1, 10)  # => true

Как работает под капотом: nil — это объект

В Ruby nil — не «пустота из ниоткуда», а единственный экземпляр класса NilClass. У него есть методы: nil.to_s даёт пустую строку, nil.to_a — пустой массив, nil.nil?true. Это удобно, но и опасно: вызов несуществующего метода на nil — самая частая ошибка новичка, знаменитый NoMethodError: undefined method for nil.

            любое выражение
                  |
        ниже только эти два — ЛОЖЬ:
                  |
          +-------+-------+
          |               |
        false            nil
          |               |
   ВСЁ ОСТАЛЬНОЕ (0, "", [], "false") --> ИСТИНА

Та же идея «безопасного обращения к возможному nil» есть и в Python через проверку на None:

# Та же логика на Python ▶
user = None
# защищаемся от обращения к None
name = user.upper() if user is not None else "гость"
print(name)   # гость

Частые ошибки

  • Ждать, что 0 или "" — ложь. В Ruby они истинны. Если нужно проверить «пусто ли», используйте .empty? или .zero?.
  • Вызывать методы на nil. Если переменная может быть nil, защищайтесь оператором безопасной навигации &.user&.name вернёт nil, а не упадёт.
  • Путать = и ==. Один знак — присваивание, два — сравнение. В условии это особенно коварно.

Best practices

  • Используйте предикатные методы (с ?): arr.empty?, n.zero?, x.nil? — они выразительнее ручных сравнений.
  • Для значения по умолчанию применяйте value || "по умолчанию" — если value ложно (nil/false), возьмётся правое.
  • Защищайте цепочки вызовов оператором &., когда звено может оказаться nil.

Глубже: операторы || и && как инструменты

Логические операторы в Ruby — не только про «истину и ложь», но и про выбор значений, и это меняет стиль кода. Оператор || возвращает первый «истинный» операнд, поэтому идиома name = input || "гость" читается как «возьми input, а если он nil или false — подставь гостя». Парный оператор && возвращает последний операнд, если все истинны, что удобно для безопасных цепочек: user && user.admin? не упадёт, даже если user равен nil. Есть и присваивающая форма ||=: запись @cache ||= compute означает «вычисли и запомни, только если ещё не вычислено» — классический приём ленивой инициализации и кэширования. Понимание того, что эти операторы возвращают не true/false, а сами значения операндов, открывает целый пласт лаконичных идиом. Главное — не переусердствовать: когда цепочка || и && разрастается, читаемость падает, и обычный if снова становится предпочтительнее.

Итог. Ложны только false и nil — всё остальное истинно. nil — это объект класса NilClass, и обращение к его методам как к обычному объекту приводит к NoMethodError. Спасает безопасная навигация &..

Проверьте себя
1. Какие значения в Ruby считаются «ложными» в условиях?
Afalse, nil, 0 и пустая строка
BТолько false и nil
CТолько nil
D0, пустая строка и пустой массив
2. Что вернёт оператор «космического корабля» 3 <=> 5?
Atrue
B-1
C1
D0