¿Qué significa el método to proc?


Estoy aprendiendo rails y siguiendo este hilo. Estoy atascado con el método to_proc. Considero los símbolos solo como alternativas a las cadenas (son como cadenas pero más baratas en términos de memoria). Si hay algo más que me falta para los símbolos, entonces por favor dime. Por favor, explique de manera sencilla lo que significa to_proc y para qué se utiliza.

Author: Community, 2013-02-14

4 answers

Algunos métodos toman un bloque, y este patrón aparece con frecuencia para un bloque:

{|x| x.foo}

Y a la gente le gustaría escribir eso de una manera más concisa. Para hacer eso, un símbolo, el método Symbol#to_proc, el casting implícito de clase y el operador & se usan en combinación. Si coloca & delante de una instancia Proc en la posición del argumento, se interpretará como un bloque. Si combina algo que no sea una instancia Proc con &, entonces la transmisión de clase implícita intentará convierta eso a una instancia Proc usando el método to_proc definido en ese objeto si hay alguno. En el caso de una instancia Symbol, to_proc funciona de esta manera:

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

Por ejemplo, supongamos que escribes así:

bar(&:foo)

El operador & se combina con :foo, que no es una instancia Proc, por lo que implicit class cast le aplica Symbol#to_proc, lo que da ->x{x.foo}. El & ahora se aplica a esto y se interpreta como un bloque, que da:

bar{|x| x.foo}
 85
Author: sawa,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-02-14 19:06:39

La forma más fácil de explicar esto es con algunos ejemplos.

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

Es lo mismo que:

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

Y

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

Es lo mismo que:

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

To_proc devuelve un objeto Proc que responde al método dado por símbolo. Así que en el tercer caso, la matriz [1,2,3] llama a su método de recogida y. succ es el método definido por la matriz de clases. Así que este parámetro es una forma corta de decir recoger cada elemento en la matriz y devolver su sucesor y a partir de eso crear una nueva matriz lo que resulta en [2,3,4]. El símbolo: succ se está convirtiendo en un objeto Proc por lo que llama al método succ de la matriz.

 42
Author: Dillon Benson,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-02-14 18:38:23

Para mí la explicación más clara es ver una simple implementación de la misma. Esto es lo que podría parecer si estuviera reimplementando el símbolo # 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
Author: Keith Bennett,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-11-10 07:59:48

Para cualquiera que todavía esté un poco perplejo, ejecutar el siguiente código podría hacer las cosas un poco más claras:

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

Estas no son las implementaciones reales de Symbol.to_proc o Array.map, son solo versiones simplificadas que estoy usando para demostrar cómo funcionan map &:to_s y llamadas similares.

 1
Author: Gerry,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-04-26 05:48:58