2010-02-18 25 views
13

¿Qué está pasando aquí? ¿Cuál es la diferencia sutil entre las dos formas de "a menos"?En Ruby, ¿por qué `foo = true a menos que esté definido? (Foo)` hacer la tarea?

> irb(main):001:0> foo = true unless defined?(foo) 
=> nil 
irb(main):002:0> unless defined?(fooo) ; fooo = false ; end 
=> false 

THX

+0

¿Qué versión de Rubí está usando? – bta

+1

Con todo esto de asignar variables a menos que ya estén definidas, me siento obligado a señalar que 'foo || = true' logra lo mismo (y siempre devuelve' true'). –

+1

@Allison R. No si 'foo' está definido pero es falso. – FMc

Respuesta

15

Aparentemente, ruby ​​crea una variable local en el tiempo de análisis, configurándolas en nil, por lo que se define y esto se hace tanto si el código se ejecuta como si no.

Cuando se evalúa el código en su primera línea, no ejecuta la parte de asignación ya que foo se establece en nil. En la segunda línea, porque fooo aún no se ha analizado, defined? devuelve nil dejando que se ejecute el código dentro del bloque y asigne fooo.

A modo de ejemplo se puede probar esto:

if false 
    foo = 43 
end 
defined? foo 
=> "local-variable" 

Esto está tomado de un foro post en rubí foro.

+0

Excelente ejemplo: debería haber pensado en simplificar el problema más allá del que mostró. Gracias. – farhadf

+0

buena explicación del comportamiento complejo –

-1

Bueno .. Una forma es un bloque y una forma no lo es. La segunda parte, el bloque, devuelve la última declaración evaluada. El primero ... Hrm ... No sé exactamente qué está haciendo.

+0

-1 Esto no involucra bloques. –

-1

en Ruby 1.8.7:

foo = true unless defined?(foo) 
p foo # => nil 

unless defined?(fooo); fooo = true; end 
p foo # => nil 

no tengo una explicación para el comportamiento que está viendo.

+0

'fooo' (en oposición a' foo') es cierto. –

2
irb(main)> foo = true unless defined?(Integer) 
=> nil 
irb(main)> foo = true unless defined?(thisIsUndefined) 
=> true 

Su primer bloque está volviendo nil porque la forma en que está escrito hojas 2 opciones:

  • foo no está definido -> asignar cierto
  • foo se define -> hacer nada

Aquí, foo debe definirse cuando se evalúa la línea. Por lo tanto, no ocurre nada y se devuelve nil.

irb(main)> unless defined?(Integer) ; fooo = false ; end 
=> nil 
irb(main)> unless defined?(thisIsUndefined) ; fooo = false ; end 
=> false 

Su segundo bloque funciona del mismo modo que su primer bloque. Si fooo no está definido, se ingresa el bloque y fooo se establece en false. El resultado de la última línea del bloque es el valor de retorno del bloque, por lo tanto, está viendo el false. Si fooo existe, entonces el bloque se omite y no ocurre nada, por lo tanto, no hay nada que devolver, por lo tanto, el nil.

De acuerdo con su código, yo diría que foo se definió cuando se ejecutó este código y fooo no (el código de prueba que se muestra se generó en Ruby 1.8.6). Si no definió ninguno de estos antes de ejecutar este código, entonces puede tener algo llamado foo que está definido por defecto (haga defined?(foo) por sí mismo para verificarlo). Intente usar un nombre diferente y vea si obtiene los mismos resultados.

Editar:

irb(main)> defined?(bar) 
=> nil 
irb(main)> bar = true unless defined?(bar) 
=> nil 
irb(main)> defined?(bar) 
=> "local-variable" 

Al parecer, defined?() está volviendo cierto, puesto que ya ha visto bar (al comienzo de la línea), a pesar de que todavía está en el proceso de definición de la misma.

1

en la primera instancia que llama al foo en existencia en la declaración de asignación. Tal vez esto se aclarará:

bar = if true 
     puts bar.class 
     else 
     puts "not reached" 
     end 
NilClass 
=> nil 

baz = if true 
     puts baz.class 
     42 
     else 
     puts "not reached" 
     end 
NilClass 
=> 42 
12

Vamos a empezar con algo más simple:

# z is not yet defined 
irb(main):001:0> defined?(z) 
=> nil 

# Even though the assignment won't execute, 
# the mere presence of the assignment statement 
# causes z to come to life. 
irb(main):002:0> z = 123 if false 
=> nil 
irb(main):003:0> defined?(z) 
=> "local-variable" 
irb(main):004:0> z 
=> nil 

Ahora podemos calcular su primer ejemplo.

foo = true unless defined?(foo) 

¿foo está definido? Antes de presionar ENTER en irb, no. Sin embargo, la presencia de la instrucción de asignación hace que foo cobre vida. Esto significa que la instrucción de asignación no se ejecutará, dejando foo en existencia pero teniendo nil como su valor. ¿Y cuál es la última expresión evaluada en la línea irb? Es unless defined?(foo), que evalúa a nil.

Para obtener más información sobre cómo las asignaciones (incluso aquellas que no se ejecutan) hacen que las variables existan, consulte esta discusión de Variable/Method Ambiguity.

En el segundo ejemplo, no hay nada misterioso en absoluto: fooo no está definido, por lo que el código en los ejecuta el bloque, el establecimiento de fooo a false. Esa asignación es la última expresión evaluada, por lo que false es el valor de retorno de nuestro bloque.

1

agosto todo parezca bien en 1.8.7:

$ irb 
irb(main):001:0> unless defined?(fooo); fooo = true; end 
=> true 
irb(main):002:0> fooo 
=> true 
irb(main):003:0> `ruby --version` 
=> "ruby 1.8.7 (2008-06-20 patchlevel 22) [i486-linux]\n" 
Cuestiones relacionadas