2010-06-06 16 views
7

Cuando a no está definido, entonces a || 1 arrojará un error, pero a = a || 1 no lo hará. ¿No es eso un poco inconsistente?¿Por qué en Ruby, a || 1 lanzará un error cuando `a` no está definido, pero a = a || 1 no?

irb(main):001:0> a 
NameError: undefined local variable or method 'a' for main:Object 
     from (irb):1 
     from c:/ruby/bin/irb:12:in '<main>' 

irb(main):002:0> a || 1 
NameError: undefined local variable or method 'a' for main:Object 
     from (irb):2 
     from c:/ruby/bin/irb:12:in '<main>' 

irb(main):003:0> a = a || 1 
=> 1 
+0

Duplicado de http://stackoverflow.com/questions/1462407/ruby-edge-cases –

Respuesta

9
a 

Aquí, usted está evaluando a, que no está definido. Por lo tanto, obtienes una excepción.

a || 1 

Aquí, todavía tiene que evaluar a para determinar el valor de la expresión booleana. Al igual que arriba, a no está definido. Por lo tanto, obtienes una excepción.

a = a || 1 

Aquí, a es definido. Se define como una variable local no inicializada. En Ruby, las variables no inicializadas evalúan a nil, por lo que el lado derecho de la expresión de asignación evalúa a nil || 1, por lo que el valor de retorno de la expresión de asignación es 1 y el efecto secundario es a que se inicializa en 1.

EDITAR: Parece que hay cierta confusión sobre cuándo se definen las variables y cuándo se inicializan en Ruby. El get se definió en parse time pero se inicializó en runtime. Se puede ver aquí:

foo # => NameError: undefined local variable or method `foo' for main:Object 

foo no está definido.

if false 
    foo = 'This will never get executed' 
end 

En este punto, foo se define, a pesar de que la línea nunca se ejecutan. El hecho de que la línea nunca se ejecute es completamente irrelevante, porque el intérprete no tiene nada que ver con esto de todos modos: las variables locales son definidas por el analizador, y el analizador obviamente ve esta línea.

foo # => nil 

no hay error, porque foo se define y se evalúa como nil porque es inicializado.

+0

+1, aunque creo que decir "Se define como una variable local no inicializada". es un poco confuso Cuando haces 'var = expr', no estás definiendo' var' para que no se inicialice. Está definiendo var como el valor de 'expr'. Es solo que mientras 'expr' evalúa,' var' pasa a estar sin inicializar, lo que significa que cualquier referencia a 'var' dentro de' expr' se evaluará a nil. – sepp2k

+1

@ sepp2k: Son dos pasos muy separados. La definición de la variable ocurre en el analizador, la inicialización en el intérprete. Dependiendo de la implementación de Ruby, puede haber un tiempo significativo entre los dos eventos. En BlueRuby, por ejemplo, el código fuente de Ruby se analiza en BRIL (BlueRuby Intermediate Language), que luego se almacena en una base de datos, cuando * instala * un programa de Ruby. Pueden pasar * años * hasta que alguien * ejecute * el programa. Todo este tiempo, la variable se definió pero no se inicializó. Las dos cosas podrían incluso suceder en diferentes máquinas. –

1

Al hacer a || 1, estás pidiéndole que busque el valor de a que es indefinido.

Cuando lo hace a = a || 1 le pide que busque el valor de asignar a a a que no parece dar un error.

Así que, aunque extraño, no creo que sea inconsistente.

+0

Esto está mal.'a = a || 1' no analiza como '(a = a) || 1'. Se analiza como 'a = (a || 1)', por lo que el resultado de "asignar a a" no tiene nada que ver con eso, porque a nunca se asigna a a. – sepp2k

+0

@ sepp2k: No estaba tratando de dar a entender eso en absoluto. Lo siento si te confundí. Creo que Jörg lo ha explicado más claramente. – Cetra

0

¿Es esto lo que quieres decir?

if !(defined? a) then 
    a = 1 
end 

Puede ser más simple declarar el valor con 1 como valor predeterminado.

Cuestiones relacionadas