Pull to refresh

Унарный амперсанд

Reading time1 min
Views5K
Расскажу как в Ruby работает такая элегантная конструкция:

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.

UPD. Примерчик


Такое свойство Symbol дает удивительную возможность вызывать методы, подставляя объекты в качестве параметров:

:upcase.to_proc.call "asdad"     # => "ASDAD"


Материалы по теме


blog.hasmanythrough.com/2006/3/7/symbol-to-proc-shorthand
weblog.raganwald.com/2008/06/what-does-do-when-used-as-unary.html
en.wikibooks.org/wiki/Ruby_Programming/Syntax/Method_Calls#The_ampersand_.28.26.29
m.onkey.org/let-s-start-with-wtf
Tags:
Hubs:
Total votes 64: ↑59 and ↓5+54
Comments17

Articles