Переменные, числа и арифметика
Переменная — это имя, привязанное к значению. В Ruby её не нужно объявлять заранее и указывать тип: присвоили значение — переменная появилась.
Суть: переменные в Ruby — это ссылки на объекты, имена пишутся через snake_case, а числа делятся на целые (Integer) и дробные (Float), причём деление целых даёт целое.
Динамическая типизация Ruby означает, что одна и та же переменная может в разные моменты ссылаться на число, строку или массив. Тип принадлежит значению, а не имени. Это даёт гибкость, но требует внимательности: Ruby не предупредит на этапе «компиляции», что вы складываете строку с числом.
age = 25
price = 19.99
total = age * 2
puts total # => 50
puts price.class # => Float
puts age.class # => Integer
Разбор: целые против дробных
Главная ловушка арифметики — деление целых чисел. 7 / 2 в Ruby равно 3, а не 3.5, потому что оба операнда целые и результат тоже целый. Чтобы получить дробь, хотя бы один операнд должен быть Float.
puts 7 / 2 # => 3 (целочисленное деление)
puts 7.0 / 2 # => 3.5 (есть Float — результат Float)
puts 7 % 2 # => 1 (остаток от деления)
puts 2 ** 10 # => 1024 (возведение в степень)
puts 7.fdiv(2) # => 3.5 (явное дробное деление)
Та же логика на Python работает идентично по сути (целые против дробных), хотя в Python 3 оператор / всегда даёт дробь, а целочисленное — это //:
# Та же логика на Python ▶
print(7 // 2) # 3 целочисленное деление
print(7 / 2) # 3.5 обычное деление
print(7 % 2) # 1 остаток
print(2 ** 10) # 1024 степень
Как работает под капотом
Когда вы пишете x = "hello", переменная x не «содержит» строку — она хранит ссылку на объект-строку в памяти. Если вы напишете y = x, обе переменные будут указывать на один и тот же объект. Это важно понимать сразу, потому что изменение объекта через одну ссылку увидят все остальные.
x = "hello" y = x
x ---> [ "hello" ] x ---> [ "hello" ]
y -----^
(один объект, две ссылки)
Числа же в Ruby ведут себя как неизменяемые (immutable) значения: операция x + 1 не меняет старое число, а создаёт новое. Поэтому с числами «общая ссылка» проблем не создаёт.
Частые ошибки
- Целочисленное деление там, где ждали дробь.
average = sum / countпри целых даст округлённый вниз результат. Используйтеfdivили приведите к Float. - camelCase в именах. В Ruby принято
snake_case:user_name, а неuserName. Имя с заглавной — это уже константа. - Сложение строки и числа.
"возраст: " + 25упадёт с ошибкой. Нужна интерполяция или.to_s.
Best practices
- Давайте переменным говорящие имена:
total_priceлучше, чемtpилиx. - Большие числа разделяйте подчёркиванием для читаемости:
1_000_000— это валидный синтаксис и равно миллиону. - Если нужна точность в деньгах, не используйте Float (он округляет неточно) — берите
BigDecimalили храните копейки в целых.
Глубже: типы чисел и точность
Стоит чуть подробнее разобраться с числовыми типами, потому что на них основано множество тонких ошибок. Целые числа (Integer) в Ruby не имеют верхнего предела: язык автоматически переключается на «длинную арифметику», когда число перестаёт помещаться в машинное слово. Поэтому 100 ** 100 честно посчитается без переполнения — приятное отличие от языков с фиксированным размером целых. Дробные числа (Float) хранятся в формате двойной точности IEEE 754, и здесь кроется классическая ловушка: 0.1 + 0.2 не равно ровно 0.3, потому что эти дроби не представимы точно в двоичной системе. Для обычных вычислений это незаметно, но в деньгах или сравнениях на равенство — катастрофа. Решений два: либо работать с целыми (хранить копейки, а не рубли), либо использовать класс BigDecimal, который считает в десятичной системе без потери точности. Запомните это правило сразу: Float — для приблизительных величин, BigDecimal или целые — для денег.
Итог. Переменные — это именованные ссылки на объекты, тип динамический и принадлежит значению. Помните о ловушке целочисленного деления и пишите имена через snake_case.