2010-05-24 26 views
18

yo estaba pasando por un ejemplo de la programación en el libro Ruby:Operador de asignación paralela en Ruby

def fib_up_to(max) 
    i1, i2 = 1, 1 # parallel assignment (i1 = 1 and i2 = 1) 
    while i1 <= max 
    yield i1 
    i1, i2 = i2, i1+i2 
    end 
end 
fib_up_to(100) {|f| print f, " " } 

Esto simplemente imprime los números de Fibonacci hasta 100. Eso está bien. Cuando reemplazo la asignación en paralelo con:

i1 = i2 
i2 = i1+i2 

No obtengo la salida deseada.

¿Es aconsejable utilizar asignaciones paralelas? Vengo de un entorno Java y me parece realmente extraño ver este tipo de tarea.

Una pregunta más es: ¿la asignación en paralelo es un operador?

Respuesta

30

El problema con hacer la asignación en 2 declaraciones separadas es que i2 = i1 + i2 utilizará el nuevo valor de i1 en lugar del valor anterior requerido para generar correctamente la secuencia de Fibonacci.

Cuando utiliza la asignación en paralelo, todas las expresiones en el lado derecho se evalúan primero y luego se asignan a las variables de recepción en el lado izquierdo.

La asignación en paralelo no es un operador especial. Esencialmente, lo que está en el lado derecho actúa como una matriz donde si listamos múltiples variables en el lado izquierdo, entonces la matriz se desempaqueta y se asigna a las variables respectivas.

Estos son algunos ejemplos más:

irb(main):020:0> a = 1, 2 # assign to a single variable 
=> [1, 2] 
irb(main):021:0> a 
=> [1, 2] 
irb(main):022:0> a, b = 1, 2 # unpack into separate variables 
=> [1, 2] 
irb(main):023:0> a 
=> 1 
irb(main):024:0> b 
=> 2 
irb(main):025:0> a, b = [1, 2, 3] # 3 is 'lost' as no receiving variable 
=> [1, 2, 3] 
irb(main):026:0> a 
=> 1 
irb(main):027:0> b 
=> 2 
irb(main):028:0> first, *rest = [1, 2, 3] # *rest consumes the remaining elements 
=> [1, 2, 3] 
irb(main):029:0> first 
=> 1 
irb(main):030:0> rest 
=> [2, 3] 

Es una característica útil de rubí, por ejemplo que facilita tener métodos que devuelven varios valores, por ejemplo,

def sum_and_difference(a, b) 
    a + b, a - b 
end 

sum, difference = sum_and_difference 5, 3 

En Java lo más parecido sería tener un método que devuelve int[] pero si queríamos devolver una cadena y un número tendríamos que crear un pequeño POJO para actuar como estructura para el valor de retorno o devuelve Object[] y desordena el código con moldes. Ver this other question que respondí recientemente para un ejemplo más práctico.

+0

Gracias mikej !! – bragboy

+2

También puede hacer: [1] '* from_first, last = 1,2,3,4' [2a]' * from_first => [1,2,3] ' [2b]' last = 4' – funfuntime

2

Estaba leyendo lo mismo y tenía la misma pregunta. Sería menos confuso y más sentido si se hubiera escrito así:

def fib_up_to(max) 
    i1 = i2 = 1 
    while i1 <= max 
    yield i1 
    i1, i2 = i2, i1+i2 
    end 
end 

fib_up_to(100) {|f| print f, " " } 

Usando i1, i2 = 1, 1 no tiene sentido en mi opinión. Pero ese tipo de asignación tiene sentido para la línea 5.

+0

Generalmente soy un poco cuidadoso con el tipo de asignaciones 'a = b = 1', ya que no es estrictamente lo mismo que' a = 1; b = 1', pero 'a = (b = 1)', es decir, "let' a' es el resultado de' b = 1' ". – Frost

+3

@Frost ¿Cuál es un ejemplo de por qué esa no es una buena idea o qué podría salir mal? –

Cuestiones relacionadas