Что вы называете оператором &: в Ruby?

Возможные дубликаты:
Рубины/Рубины на Rails-амперсанде. Что означает map (&: name) в Ruby?

Я читал Stackoverflow и наткнулся на следующий код

array.map(&:to_i)

Хорошо, это легко увидеть, что делает этот код, но я хотел бы узнать больше о конструкторе &:, который я никогда раньше не видел.

К сожалению, все, о чем я могу думать, это "лямбда", которого нет. Google сообщает мне, что синтаксис лямбда в Ruby равен ->->(x,y){ x * y }

Итак, кто-нибудь знает, что такое таинственное &: и что он может делать, кроме вызова одного метода?

Ответ 1

Здесь несколько движущихся частей, но имя для того, что происходит, - это Symbol#to_proc. Это часть Ruby 1.9 и выше, а также доступна, если вы используете более поздние версии Rails.

Во-первых, в Ruby :foo означает "символ foo", поэтому на самом деле это два отдельных оператора, на которые вы смотрите, а не один большой оператор &:.

Когда вы говорите foo.map(&bar), вы сообщаете Ruby, "отправьте сообщение объекту foo, чтобы вызвать метод map, с уже определенным мной блоком bar". Если bar уже не является объектом Proc, Ruby попытается сделать его одним.

Здесь мы фактически не передаем блок, а вместо него символ bar. Поскольку мы имеем неявное преобразование to_proc, доступное в Symbol, Ruby видит это и использует его. Оказывается, это преобразование выглядит следующим образом:

def to_proc
  proc { |obj, *args| obj.send(self, *args) }
end

Это делает Proc, который вызывает метод с тем же именем, что и символ. Объединяя все это, используя исходный пример:

array.map(&:to_i)

Это вызывает .map в массиве, и для каждого элемента в массиве возвращает результат вызова to_i этого элемента.