Еще одна заметка о блоках Ruby

Если вы уже некоторое время программируете на Ruby, то, скорее всего, уже использовали встроенные методы, такие как #each, #select и #map. Несмотря на то, что все говорят о магии Ruby, нет ничего особенного в том, как работают эти методы.

Эти методы обычно вызываются на коллекциях, таких как массивы и хэши, либо с помощью инлайн-блока (код, заключенный в фигурные скобки), либо многострочного блока (код, заключенный между do и end).

Как работают блоки?

Мы часто связываем блоки кода с методами, которые доступны нам через модуль Enumerable. Пожалуйста, посмотрите на пример ниже:

  1. Инлайн-блок:
[1, 2, 3, 4, 5].select { |number| number.even? }

> [2, 4]
Войти в полноэкранный режим Выход из полноэкранного режима
  1. Многострочный блок:
[1, 2, 3, 4, 5].select do |number|
  number.odd?
end

> [1, 3, 5]
Войти в полноэкранный режим Выход из полноэкранного режима

Для того чтобы полностью понять, как работают блоки, необходимо научиться создавать собственные пользовательские блоки, чтобы понять все тонкости!

Передача управления блоку

Любой метод в Ruby может быть связан с блоком, но то, что определяет, будет ли этот блок вызван или нет во время выполнения метода, — это специальное ключевое слово yield.

roll_die { |number| puts "You rolled #{number}" }
Вход в полноэкранный режим Выход из полноэкранного режима

Как мы могли бы реализовать этот метод?

def roll_die
  puts "Method is executing..."
  random_number = rand(1..6)
  yield(random_number)
  puts "Method is done!"
end
Войти в полноэкранный режим Выйти из полноэкранного режима

Поэтому, как только мы вызовем метод roll_die с ассоциированным блоком, он выведет в консоль следующие строки:

> "Method is executing..."
> "You rolled 3"
> "Method is done!"
Вход в полноэкранный режим Выход из полноэкранного режима

Что делает yield, так это «приостанавливает» выполнение метода roll_die и передает управление блоку, который с ним связан. Кроме того, он также передает параметр random_number в качестве параметра блока!

Любопытным свойством блоков является то, что после завершения их выполнения они возвращают последнюю вычисленную строку кода в качестве конечного результата! Подождите секунду… что это значит?

Это значит, что вместо этого мы могли бы сделать что-то вроде этого:

  • Перестановка кода в методе roll_die:
def roll_die
  puts "Method is executing..."
  random_number = rand(1..6)
  result = yield(random_number)
  puts "You rolled #{result}"
  puts "Method is done!"
end
Вход в полноэкранный режим Выход из полноэкранного режима
  • Переупорядочивание блока кода, связанного с методом roll_die:
roll_die do |number|
  puts "Rolling the die..."
  number
end
Вход в полноэкранный режим Выход из полноэкранного режима

В новом расположении случайное число возвращается методом yield и присваивается переменной result в методе roll_die!

> "Method is executing..."
> "Rolling the die..."
> "You rolled 1"
> "Method is done!"
Вход в полноэкранный режим Выход из полноэкранного режима

Предостережения о блоках Ruby

Если вы дочитали до этого места, вам, вероятно, интересно, что произойдет, если мы попытаемся выполнить yield, но не будет связанного блока, которому можно передать управление. Для таких случаев мы можем использовать метод block_given?. Посмотрите пример ниже:

  • Определение метода greeting(name):
def greeting(name)
  if block_given?
    yield(name)
  else
    "No block was given."
  end
end
Вход в полноэкранный режим Выход из полноэкранного режима
  • Ассоциирование метода greeting(name) с блоком:
greeting(name) { |name| "Hello,  #{name}!" }
Вход в полноэкранный режим Выход из полноэкранного режима

Теперь есть 2 различных способа вызвать метод greeting(name):

# First way
greeting("Mary") { |name| "Hello,  #{name}!" }

> "Hello,  #{name}!"

# Second way
greeting("John")

> "No block was given."
Войти в полноэкранный режим Выйти из полноэкранного режима

Еще один любопытный вопрос связан с количеством параметров, передаваемых в yield, которые в свою очередь отправляются как параметры блока в ваш блок. Принуждает/требует ли их Ruby или нет? Попробуйте, используя irb — вы будете удивлены результатом!

Пожалуйста, дайте мне знать, если у вас есть какие-либо вопросы и/или предложения в комментариях ниже!

Оцените статью
devanswers.ru
Добавить комментарий