Почему Ruby позволяет обращаться к методам только с помощью символов при вызове to_proc для них?

Это работает:

strings = ["1", "2", "3"]
nums = strings.map(&:to_i)

Мы видим, что & (метод to_proc), примененный к объекту Symbol, превращается в блок. Однако это не работает:

strings = ["1", "2", "3"]
nums = strings.map(&to_i)
nums = strings.map("to_i".to_sym.to_proc) #...neither does this

Почему это не работает? Нет ли альтернативного способа написать код выше? Я запутался, потому что есть два способа получить доступ к методу класса:

"1".method(:to_i).call #works as well as
"1".method("to_i").call 

Таким образом, к имени метода можно получить доступ либо по символу, либо по строке.


person Froschgesicht    schedule 18.01.2016    source источник


Ответы (2)


Учитывая следующий допустимый пример Ruby:

"to_i".to_sym.to_proc.call("1")

Чтобы вызвать #to_proc для символа, создается процесс, который получает один параметр: объект, который должен получить вызов метода, названного символом. Что-то вроде этого:

->(object) {
  object.send(:to_i)
}

Что делает &, так это передает блок, возвращенный #to_proc, как правильный блок вызова вызываемому методу. При использовании с Enumerable#map окончательный результат заключается в том, что переданный блок будет вызываться для каждого элемента в коллекции и получать текущий элемент итерации, передаваемый в качестве параметра блоку.

Таким образом, синтаксис ["1", "2"].map(&:to_i) — это сокращение от чего-то вроде этого:

block = ->(el) {
  el.send(:to_i)
}

["1", "2"].map &block

О ваших примерах:

Когда вы попытаетесь вызвать &to_i в своем примере, Ruby попытается вызвать переменную или метод с именем to_i. Поскольку он не существует в области (это метод каждого String в Array, а не в «глобальной» области), он выдаст ошибку.

О другом примере: "to_i".to_sym.to_proc преобразует :to_i в процедуру, которая при вызове с одним параметром попытается вызвать метод, названный в честь символа (:to_i) для целевого параметра. Это означает, что вы можете использовать & для преобразования процедуры в «блок вызова»:

["1", "2"].map(&"to_i".to_sym.to_proc)
person Ricardo Valeriano    schedule 18.01.2016

nums = strings.map(&to_i)

не работает, потому что to_i не определен в основной среде.

nums = strings.map("to_i".to_sym.to_proc)

не работает, потому что экземпляр Proc не является блоком. Блок - это даже не объект.

Ты можешь написать:

nums = strings.map(&"to_i".to_sym)
person sawa    schedule 18.01.2016