Pregunta

Recientemente intenté hacer algo parecido a esto:

a = "some string"
b = Proc.new{ upcase }
a.instance_eval b

Que da el error:

TypeError: no se puede convertir Proc en cadena

Pero esto funciona:

def b(&block)
  "some string".instance_eval &block
end

b{ upcase }

Una mirada adicional con este método:

def b(&block)
  "some string".instance_eval block
end

Produce lo mismo Proc to String error.

Entonces ... mi comprensión de los bloques es que son solo procs. Pero obviamente hay algo especial en tener esto & ampersand ...

¿Alguien puede explicarme esto? ¿Es posible convertir un proceso normal para ser lo que sea que sea especial sobre esto? &block ¿objeto?

editar

Acabo de descubrir mi segunda pregunta, prependa un & Para el proceso ... eso fue fácil, pero ¿qué está haciendo realmente esto?

¿Fue útil?

Solución

Todo lo que tiene que hacer para que su primer ejemplo funcione es esto:

>> a.instance_eval &b #=> "SOME STRING"

La razón es que instance_eval necesita una cadena o un bloque y el ampersand proporciona el último.

Para comprender las diferencias entre bloques y procesos, tal vez la siguiente publicación de blog ayuda:

Comprender los bloques de rubí, procs y lambdas

Otros consejos

La diferencia es que a.instance_eval b está pasando b como un argumento regular a instancia_eval, mientras que a.instance_eval &b lo está pasando como un bloque. Esas son dos cosas diferentes.

Considere esta llamada de método:

obj.foo(bar) do |x| 
  stuff(x) 
end

Que invoca el método foo con un argumento regular (bar) y un argumento de bloque (do |x| stuff(x) end). En la definición del método, se distinguen prefijando & al parámetro de bloque:

def foo(arg, &block)

Y si desea pasar una expresión variable en lugar de un bloque literal, eso también se logra mediante el prefijo & a la expresión (que debería producir un proc).

Si pasa una discusión sin ningún &, entra en el argumento ranura en lugar de la bloquear ranura. No importa que el argumento sea una instancia de Proc. La sintaxis dicta cómo se pasa y se trata por el método.

Es porque instance_eval acepta una cadena para evaluar o un bloque. instance_eval(&block) está pasando tu block como un bloque a instancia_eval.

La diferencia crucial es que Una instancia de proc es un objeto mientras Un bloque no es un objeto. los & es un operador que intercambia un bloque y una instancia de proc mutuamente.

Todos los argumentos a un método deben ser un objeto. Además de los argumentos, un método puede tomar un bloque. instance_eval es un método que toma un argumento de cadena o un bloque. Pasar un objeto PROC no satisfará ninguno de los casos. Si adjuntas & a un objeto de proc, eso será a mano como un bloque.

Esto funcionará:

a = "some string"
b = Proc.new{ upcase }
a.instance_eval &b

los instance_eval El método puede recibir un bloque de argumentos.b es un Proc.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top