def contrived(a, &f) # блок (block) может быть доступен через f f.call(a) # но yield также работает! yield(a) end
def some_method(&block)
block.class
end
Объяснение этой элегантности можно найти в Унарный амперсанд
Рассмотрим пример:
User.all.map &:name # получить массив имен пользователей
вместо
User.all.map { |user| user.name }
Сначала кажется что это свойство перечисляемых классов, но на самом деле это не так.
Магия #1.
Когда ruby встречает амперсанд (&) в последнем аргументе вызова метода,то пытается превратить его в выполняемый блок кода (Proc). Например:
a = (1..10).to_a
a.map { |n| n*n } # => [1, 4, 9, 16, 25, 36, 49, 64, 81, 100]
l = lambda { |n| n*n }
a.map &l # => [1, 4, 9, 16, 25, 36, 49, 64, 81, 100]
Магия #2.
Ruby, встречая амперсанд, превращает обьект в выполняемый блок через вызов метода #to_proc.И вот он главный сюрприз, вызывая #to_proc у Symbol мы получаем примерно следующий блок кода:
lambda { |x| x.send(self) }
То есть Symbol#to_proc возвращет именно тот блок, который мы от него ожидали, потому что он в таком виде уже определен в классе Symbol.
Пару слов про:
def some_method(&block)
block.class
end
В этом примере знак & - это способ отметить аргумент, который будет соответствовать передаваемому блоку.
Для вызова блока нужно вызвать метод call у нашего блока c требуемыми параметрами (our_block.call(x)
)
Давайте узнаем, чем же на самом деле в последнем примере является наш блок (block
).
puts some_method {}
# => Proc
Вот такие чудеса.
Комментариев нет:
Отправить комментарий