ruby - blocks - ¿Qué significa el método to_proc?
ruby pass block as argument (4)
Algunos métodos toman un bloque, y este patrón aparece frecuentemente 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 lanzamiento de clase implícito y el operador &
se usan en combinación. Si coloca &
delante de una instancia de Proc
en la posición de argumento, se interpretará como un bloque. Si combina algo que no sea una instancia de Proc
con &
, entonces la conversión de clase implícita intentará convertirla en una instancia de Proc
utilizando el método to_proc
definido en ese objeto, si existe alguno. En el caso de una instancia de 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 de Proc
, por lo que la Symbol#to_proc
clase implícita aplica el Symbol#to_proc
a él, lo que da ->x{x.foo}
. El &
ahora se aplica a esto y se interpreta como un bloque, que da:
bar{|x| x.foo}
Estoy aprendiendo rieles 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 falte para los símbolos, entonces dígame. Por favor explique de manera simple lo que significa to_proc
y para qué se utiliza.
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 mediante un símbolo. Entonces, en el tercer caso, la matriz [1,2,3] llama a su método de recolección y. succ es un método definido por la clase Array. Por lo tanto, este parámetro es una forma breve de decir, recopilar cada elemento de la matriz y devolver a su sucesor, y de ahí crear una nueva matriz que dé como resultado [2,3,4]. El símbolo: succ se está convirtiendo en un objeto Proc para que llame al método succ del Array.
Para alguien que todavía esté un poco perplejo, ejecutar el siguiente código podría aclarar un poco las cosas:
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
, solo son versiones simplificadas que estoy usando para demostrar cómo funcionan el map &:to_s
y llamadas similares.
Para mí, la explicación más clara es ver una implementación simple de esto. Esto es lo que podría parecer si volviera a implementar 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''