2012-02-06 14 views
10

estoy tratando de evaluar la expresión (a=10) || (rr=20) mientras que la variable no está definida rrHace || operador evalúa el segundo argumento incluso si el primer argumento es verdadero?

por lo que escribir en la consola rr rubí antes de evaluar la expresión anterior devuelve

rr 
NameError: undefined local variable or method `rr' for main:Object 
from (irb):1 
from :0 

Cuando escribo la expresión (a=10) || (rr=20) se devuelve 10, y cuando escribo rr después se dice nil

(a=10) || (rr=20) 
rr # => nil 

es así, ¿por qué sucede esto? No debería definirse rr solo si el segundo argumento de || operador se evalúa, que nunca debe basarse en la documentación?

+1

Existe una diferencia entre las operaciones condicional en cortocircuito (no se evalúa la segunda condición si la primera es falsa) y no se declara una variable. Tu problema se relaciona con el segundo problema. – DOK

+1

Saber cuándo una variable local está en su alcance es complicado en Ruby. Intenta ejecutar 'a + 1 si a = 5'. Es de esperar que establezca un 5 y luego un 6, pero en realidad establecerá 'a' y ENTONCES se quejará de que' a' no está definido. –

Respuesta

10

Esto sucede porque el intérprete de ruby ​​define una variable cuando ve una asignación (pero antes de que ejecute la línea de código real). Puede leer más al respecto in this answer.

expresión booleana O (||) evaluará al valor de la expresión de la mano izquierda si no es nil y no false, de lo contrario || se evaluará como el valor de la expresión de la derecha.

En el ejemplo, el intérprete de Ruby ve una asignación a a y rr (pero no ejecuta esta línea aún), e inicializa (define, crea) a y rr con nil. Luego ejecuta la expresión ||. En esta expresión ||, a se asigna a 10 y 10 se devuelve. r=20 no se evalúa, y rr no se cambia (todavía es nil). Esta es la razón por la cual en la línea siguiente rr es nil.

+0

La variable * no * se inicializó, solo está definida. Es por eso que evalúa 'nil': porque las variables no inicializadas se evalúan como' nil' en Ruby. Si se * inicializa *, se evaluaría como '20', no' nil'. –

+0

@ JörgWMittag, tnx para una redacción correcta. * Inicializado * en mi respuesta realmente debería ser * definido * –

3

Creo que la definición de variable ocurre en la etapa de análisis sintáctico, no en el momento de la ejecución. Entonces cuando evalúa la línea, analiza todo y la variable se define, pero no asignada.

+0

* Exactamente *. Esta es la respuesta correcta. La variable está * definida *, porque las variables se definen cuando hay una asignación en el código. Pero * no * se inicializa o asigna, porque la asignación nunca se ejecuta. Por lo tanto, se evalúa como 'nil' porque eso es lo que evalúan las variables sin inicializar en Ruby. –

2

Cuando el analizador descubre una variable, es automáticamente válida dentro del contexto en el que está definida. Evaluar rr por sí solo no es válido. La evaluación de rr=20 es suficiente para causar una definición incluso si la asignación de valores nunca ocurre.

Esta es una peculiaridad de cómo Ruby intenta discernir entre las variables y las llamadas a los métodos. Es imperfecto, pero por lo general da lo mejor.

4

Como @DOC dijo, && y || se conocen como operadores condicionales short circuited.

In case of ||, if the left part of || expression returns true, the right part won't be executed. Eso significa que la parte derecha se ejecutará solo si la parte izquierda de la expresión || devuelve falso.

In case of &&, right part of the & & expression will be executed only if left part of && returns true.

En el escenario dado (a=10) || (rr=20), rr = 20 no se ejecutará ya que la expresión rubí a=10 rendimientos true. Tenga en cuenta que en Ruby la expresión de asignación devuelve verdadero excepto nil and false.

Cuestiones relacionadas