web-dev-qa-db-fra.com

Que signifie la méthode to_proc?

J'apprends Rails et suivants ce fil . Je suis coincé avec le to_proc méthode. Je considère les symboles uniquement comme des alternatives aux chaînes (ils sont comme des chaînes mais moins chers en termes de mémoire). S'il me manque quelque chose d'autre pour les symboles, alors dites-le moi. Veuillez expliquer de manière simple ce que to_proc signifie et à quoi il sert.

46
swapnesh

Certaines méthodes prennent un bloc, et ce modèle apparaît fréquemment pour un bloc:

{|x| x.foo}

et les gens aimeraient écrire cela de manière plus concise. Pour ce faire, un symbole, la méthode Symbol#to_proc, transtypage de classe implicite et & Les opérateurs sont utilisés en combinaison. Si vous mettez & devant une instance de Proc dans la position de l'argument, qui sera interprétée comme un bloc. Si vous combinez autre chose qu'une instance de Proc avec &, puis le transtypage de classe implicite tentera de convertir cela en une instance de Proc en utilisant to_proc méthode définie sur cet objet s'il y en a. Dans le cas d'une instance Symbol, to_proc fonctionne de cette façon:

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

Par exemple, supposons que vous écriviez comme ceci:

bar(&:foo)

Le & L'opérateur est combiné avec :foo, qui n'est pas une instance de Proc, donc le transtypage de classe implicite s'applique Symbol#to_proc, ce qui donne ->x{x.foo}. Le & s'applique maintenant à cela et est interprété comme un bloc, ce qui donne:

bar{|x| x.foo}
99
sawa

La façon la plus simple d'expliquer cela est avec quelques exemples.

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

Est le même que:

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

et

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

Est le même que:

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

to_proc renvoie un objet Proc qui répond à la méthode donnée par un symbole. Donc dans le troisième cas, le tableau [1,2,3] appelle sa méthode collect et. succ est une méthode définie par la classe Array. Donc, ce paramètre est une façon courte de dire de collecter chaque élément du tableau et de renvoyer son successeur et de créer un nouveau tableau qui donne [2,3,4]. Le symbole: succ est en cours de conversion en objet Proc, il appelle donc la méthode succ du tableau.

43
Dillon Benson

Pour moi, l'explication la plus claire est d'en voir une simple mise en œuvre. Voici à quoi cela pourrait ressembler si je réimplémentais le symbole # 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'
8
Keith Bennett

Pour quelqu'un encore un peu perplexe, l'exécution du code suivant pourrait rendre les choses un peu plus claires:

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}"

Ce ne sont pas les implémentations réelles de Symbol.to_proc ou Array.map, ce ne sont que des versions simplifiées que j'utilise pour montrer comment map &:to_s et les appels similaires fonctionnent.

1
Gerry