def contrived(a, &f)
# блок (block) может быть доступен через f
f.call(a)
# но yield также работает!
yield(a)
enddef 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
Вот такие чудеса.
Комментариев нет:
Отправить комментарий