Подтвердить что ты не робот

Что означает метод to_proc?

Я изучаю рельсы и следую этой теме. Я придерживаюсь метода to_proc. Я рассматриваю символы только как альтернативы строкам (они похожи на строки, но более дешевые с точки зрения памяти). Если есть что-то еще, что я пропускаю для символов, то, пожалуйста, скажите мне. Пожалуйста, объясните простым способом, что означает to_proc и для чего он используется.

4b9b3361

Ответ 1

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

{|x| x.foo}

и люди хотели бы написать это более сжатым способом. Для этого в комбинации используются символ, метод Symbol#to_proc, неявное литье классов и оператор &. Если вы положите & перед экземпляром Proc в позиции аргумента, это будет интерпретироваться как блок. Если вы объединяете что-то, отличное от экземпляра Proc с &, то неявное кастинг класса будет пытаться преобразовать его в экземпляр Proc, используя метод to_proc, определенный на этом объекте, если он есть. В случае экземпляра Symbol to_proc работает следующим образом:

:foo.to_proc # => ->x{x.foo}

Например, предположим, что вы пишете вот так:

bar(&:foo)

Оператор & объединяется с :foo, который не является экземпляром Proc, поэтому неявный класс применяет к нему Symbol#to_proc, что дает ->x{x.foo}. & теперь применяется к этому и интерпретируется как блок, который дает:

bar{|x| x.foo}

Ответ 2

Самый простой способ объяснить это несколькими примерами.

(1..3).collect(&:to_s)  #=> ["1", "2", "3"]

То же, что и:

(1..3).collect {|num| num.to_s}  #=> ["1", "2", "3"]

и

[1,2,3].collect(&:succ)  #=> [2, 3, 4]

То же, что и:

[1,2,3].collect {|num| num.succ}  #=> [2, 3, 4]

to_proc возвращает объект Proc, который отвечает на данный метод символом. Поэтому в третьем случае массив [1,2,3] вызывает метод сбора и. succ - метод, определяемый классом Array. Таким образом, этот параметр представляет собой короткий способ сказать, собирать каждый элемент в массиве и возвращать его преемника, и из него создать новый массив, что приводит к [2,3,4]. Символ: succ преобразуется в объект Proc, поэтому он вызывает метод succ Array.

Ответ 3

Для меня самым ясным объяснением является его простая реализация. Вот как это могло бы выглядеть, если бы я переопределял Symbol # to_proc:

class Symbol  # reopen Symbol class to reimplement to_proc method
  def to_proc
    ->(object) { object.send(self) }
  end
end

my_lambda = :to_s.to_proc

puts my_lambda.(1)  # prints '1'; .() does the same thing as .call()
puts my_lambda.(1).class  # prints 'String'

puts [4,5,6].map(&:to_s)  # prints "4\n5\n6\n"
puts [4,5,6].map(&:to_s).first.class  # prints 'String'

Ответ 4

Для кого-то еще немного запутанного, запуск следующего кода может сделать вещи немного яснее:

class Symbol
  def to_proc
    proc do |obj|
      puts "Symbol proc: #{obj}.send(:#{self})"
      obj.send(self)
    end
  end
end

class Array
  def map(&block)
    copy = self.class.new
    self.each do |index|
      puts "Array.map:   copy << block.call(#{index})"
      copy << block.call(index)
    end
    copy
  end
end

remapped_array = [0, 1, 2].map &:to_s
puts "remapped array: #{remapped_array.inspect}"

Это не фактические реализации Symbol.to_proc или Array.map, они просто упрощенные версии, которые я использую, чтобы продемонстрировать, как работают map &:to_s и подобные вызовы.