Зарегистрируйтесь, чтобы продолжить обучение

Блоки как объекты Основы Ruby

Блоки — одна из ключевых концепций в Ruby, без которой практически не обходится ни один кусок кода. Они очень похожи на обычные лямбда-функции, но имеют свои особые черты. Для хорошего понимания языка и происходящего в коде нужно понимать, как они устроены. Здесь мы немного копнем вглубь.

С одной стороны, у блоков есть особый синтаксис создания и передачи в функции как особого параметра.

# Открытие файла на запись и добавление туда строки
File.open('log.txt', 'w') { |f| f.write "[hexlet] #{Time.now} - User logged in\n" }

С другой стороны, сам блок — это объект, как и всё остальное в языке. Его можно как создать независимо от функции, так и использовать. За блоки в Ruby отвечает класс Proc:

# Немного взрывает мозг то, что блок определяется через свой же синтаксис
square = Proc.new { |x| x**2 }
# Альтернативный синтаксис — proc { |x| x**2 }
square.call(4) # 16

С объектом-блоком можно делать всё то же самое, что и с другими объектами. В этом смысле он ведет себя как анонимная функция в любом языке. Однако, если мы захотим этот объект использовать как блок при передаче в функцию, то ничего не получится:

[1, 2].map square
# ArgumentError (wrong number of arguments (given 1, expected 0))

Хотя мы и имеем дело с блоком, всё же в примере выше он передается в функцию как обычный объект первым параметром. Но метод map() не принимает на вход ничего, кроме блока, поэтому код завершается с ошибкой. Блок, созданный как объект, невозможно напрямую использовать в методах, ожидающих на вход блоки. Для этого нужен специальный синтаксис:

[1, 2].map &square # [1, 4]

Амперсанд, добавленный в начале переменной, содержащей блок, передает этот блок в функцию не как параметр, а как блок. Но тут нас ждет сюрприз:

# Завершится с ошибкой
[1, 2].map() &square

# Сработает
[1, 2].map(&square)

Это поведение не должно вас вводить в заблуждение. Выше мы видим исключительно особенности синтаксиса. Блок выше не передается как параметр, это легко увидеть, если посмотреть на определение метода map(). Он не принимает на вход никаких параметров.


Аватары экспертов Хекслета

Остались вопросы? Задайте их в разделе «Обсуждение»

Вам ответят команда поддержки Хекслета или другие студенты

Для полного доступа к курсу нужен базовый план

Базовый план откроет полный доступ ко всем курсам, упражнениям и урокам Хекслета, проектам и пожизненный доступ к теории пройденных уроков. Подписку можно отменить в любой момент.

Получить доступ
1000
упражнений
2000+
часов теории
3200
тестов

Открыть доступ

Курсы программирования для новичков и опытных разработчиков. Начните обучение бесплатно

  • 130 курсов, 2000+ часов теории
  • 1000 практических заданий в браузере
  • 360 000 студентов
Отправляя форму, вы принимаете «Соглашение об обработке персональных данных» и условия «Оферты», а также соглашаетесь с «Условиями использования»

Наши выпускники работают в компаниях:

Логотип компании Альфа Банк
Логотип компании Aviasales
Логотип компании Yandex
Логотип компании Tinkoff
Рекомендуемые программы
профессия
Программирование на Ruby, Разработка веб-приложений и сервисов используя Rails, проектирование и реализация REST API
5 месяцев
c опытом
Старт 26 декабря

Используйте Хекслет по-максимуму!

  • Задавайте вопросы по уроку
  • Проверяйте знания в квизах
  • Проходите практику прямо в браузере
  • Отслеживайте свой прогресс

Зарегистрируйтесь или войдите в свой аккаунт

Отправляя форму, вы принимаете «Соглашение об обработке персональных данных» и условия «Оферты», а также соглашаетесь с «Условиями использования»
Изображение Тото

Задавайте вопросы, если хотите обсудить теорию или упражнения. Команда поддержки Хекслета и опытные участники сообщества помогут найти ответы и решить задачу