2010-10-26 18 views
8

¿Alguien qué puedo escribir esto:Rubí, mientras que la sintaxis

ruby-1.8.7-p302 > a = %w(a b c) 
=> ["a", "b", "c"] 
ruby-1.8.7-p302 > while (i = a.shift) do; puts i ; end 
a 
b 
c 
=> nil 

que parece que pasa un bloque de tiempo. Y no :

while(i = a.shift) { puts i; } 

¿Es debido a que el "do" de la sintaxis mientras se acaba el azúcar sintáctica y como nada que ver con el "hacer" de un bloque?

+0

¡Gran pregunta! –

Respuesta

12

¿Es porque la do de la sintaxis while es sólo azúcar sintáctica y como nada que ver con el do de un bloque?

Más o menos, sí. No es azúcar sintáctica, es simplemente un constructo de lenguaje incorporado, como def o class, como @meagar ya escribió.

No tiene nada que ver con el do de un bloque, excepto que las palabras clave son caras y, por lo tanto, reutilizar palabras clave tiene sentido. (Por "cara" quiero decir que limitan el programador en su expresividad.)

En un bucle while, hay dos maneras de separar el bloque de la condición:

  1. la palabra clave do y
  2. un separador de expresiones.

Hay, a su vez, dos diferentes separadores de expresión en Ruby:

  1. el punto y coma ; y
  2. una nueva línea

Así, los tres de los siguientes son válidos:

while i = a.shift do puts i end # do 

while i = a.shift; puts i end # semicolon 

while i = a.shift 
    puts i end     # newline 

[Obvi ormente, esto último no estaría escrito de esa manera, que pondría la end en una nueva línea, dedented para que coincida con el while. Solo quería demostrar cuál es el mínimo necesario para separar las partes del lazo while.]

Por cierto: es muy poco idiomático poner la condición entre paréntesis. También hay un montón de puntos y comas superfluos en tu código. Y el nombre de variable i generalmente se reserva para un índice, no para un elemento. (Que normalmente utilizo el de elementos genéricos, pero me gusta mucho más semánticas más nombres.)

También es altamente no-idiomática para recorrer una colección manualmente.El código sería mucho mejor escrito como

a.each(&method(:puts)).clear 

No sólo es mucho más fácil de entender lo que esto (imprimir todos los elementos de la matriz y eliminar todos los elementos de ella), sino que también es mucho más fácil escribir (hay no es forma de obtener la condición de terminación incorrecta, o arruinar cualquier tarea). También resulta ser más eficiente: su versión es Θ (n), esta es Θ (n).

Y en realidad, tampoco es así como lo escribiría, porque Kernel#puts ya implementa ese comportamiento. Por lo tanto, lo que haría muy escribir es este

puts a 
a.clear 

o tal vez esto

a.tap(&method(:puts)).clear 

[Nota: este último no es 100% equivalente. Imprime una nueva línea para una matriz vacía, todas las demás imprimen nada.]

Simple. Claro. Conciso. Expresivo. Rápido.

Compare esto con:

while (i = a.shift) do; puts i ; end 

que en realidad tenía que ejecutar varias veces para estar 100% claro lo que hace.

+0

Brillante. Tengo que marcar y estudiar este. :) –

+1

Método # to_proc ... Creo que me enamoré de ti un poco jorg –

+0

excelente respuesta, muchas gracias Jörg! – marcgg

6

while hace falta ser un bloque, que es una construcción del lenguaje. El do es opcional:

while (i = a.shift) 
    puts i 
end 
Cuestiones relacionadas