2009-10-12 11 views
20

Solo brevemente, ¿por qué las tres líneas siguientes no son idénticas en su impacto?Comprender el "||" O operador en If conditionals en Ruby

if @controller.controller_name == "projects" || @controller.controller_name == "parts" 

if @controller.controller_name == ("projects" || "parts") 

if @controller.controller_name == "projects" || "parts" 

La primera me da el resultado que quiero, sino como realidad hay más opciones que sólo los proyectos y piezas, utilizando esa forma crea una declaración detallada. Los otros dos son más compactos, pero no me dan el mismo resultado.

Respuesta

38

la semántica exacta de || son:

  • si la primera expresión no es nula o falsa, devuélvalo
  • si la primera expresión es nula o falsa, volver la segunda expresión

así que lo que su primera expresión se resuelve a decir, si @controller.controller_name == "projects", la expresión cortocircuita y devuelve true. si no, verifica la segunda expresión. la segunda y tercera variantes son esencialmente if @controller.controller_name == "projects", ya que "projects" || "parts" es igual a "projects". puede probar esto en IRB:

>> "projects" || "parts" 
=> "projects" 

lo que quiere hacer es

if ["projects", "parts"].include? @controller.controller_name 
5

|| es también un operador coalescente nula, por lo

"projects" || "parts" 

volverá la primera cadena que no es nulo (en este caso "proyectos"), lo que significa que en el segundo dos ejemplos, usted siempre evaluará:

if @controller.controller_name == "projects" 

para prender IRB, se puede comprobar que esto está sucediendo:

a = "projects" 
b = "parts" 

a || b 

devuelve projects

+4

en realidad,' o 'dos cadenas juntos le daremos la primera cadena, para apoyar modismos como 'a || =" hello "' y 'a = somefunc() || default' –

+0

Tiene toda la razón. Actualicé mi respuesta. – jerhinesmith

6

La diferencia es del orden de lo que está pasando. También el || no está haciendo lo que usted cree en el 2 y 3.

También se puede hacer

if ['projects','parts'].include?(@controller.controller_name) 

para reducir código en el futuro si es necesario agregar más partidos.

2

La forma más sencilla de obtener una solución no es prolijo

if ["a", "b", "c"].include? x 

En realidad, esto no tiene nada que ver con ||, sino más bien qué valores son considerados para ser cierto en rubíes. Todo excepto falso y nada es verdad.

0

Primero se comparan los literales de cadena de "proyectos" y "partes" con la variable @controller.controller_name.

segunda evalúa ("Proyectos" || "partes"), que es "proyectos" porque "proyectos" cadena literal ni false o nil o cadena vacía y compararlo con @controller.controller_name

En tercer lugar se compara @controller.controller_name y " proyectos "y si son iguales, devuelve true, si no lo son devolverá" partes "que es igual a true para la declaración if.

1

El operador lógico u operador || funciona en expresiones booleanas, por lo que usar en cadenas no hace lo que desea.

Hay varias maneras de lograr lo que quiere que sean menos detalladas y más legibles.

Usando Array # include? y un simple instrucción if-:

if ["projects", "parts"].include? @controller.controller_name 
    do_something 
else 
    do_something_else 
end 

Usando una sentencia-case:

case @controller.controller_name 
when "projects", "parts" then 
    do_something 
else 
    do_something_else 
end 
3

Básicamente, no == Cómo distribuye sobre otros operadores. La razón 3 * (2+1) es la misma que 3 * 2 + 3 * 1 es que la multiplicación se distribuye sobre la suma.

El valor de a || la expresión será uno de sus argumentos. Por lo tanto, la segunda declaración es equivalente a:

if @controller.controller_name == "projects" 

|| es de menor precedence que ==, por lo que la tercera afirmación es equivalente a:

if (@controller.controller_name == "projects") || "ports" 
2

Hay un par de cosas diferentes que se desarrollan:

if @controller.controller_name == "projects" || @controller.controller_name == "parts" 

esto da el comportamiento que desea que estoy asumiendo. La lógica es bastante básico: return true si el nombre controladora es o "proyectos" o "partes"

Otra forma de hacer esto es:

if ["projects", "parts", "something else..."].include? @controller.controller_name 

que comprobará si el nombre del controlador está en algún lugar en el lista.

Ahora para los otros ejemplos:

if @controller.controller_name == ("projects" || "parts") 

Esto no va a hacer lo que quiera. Primero evaluará ("projects" || "parts") (lo que dará como resultado "proyectos"), y luego solo comprobará si el nombre del controlador es igual a eso.

if @controller.controller_name == "projects" || "parts" 

Este es aún más raro. Esto siempre dará como resultado verdadero. Primero comprobará si el nombre del controlador es igual a "proyectos". Si es así, la declaración se evalúa como verdadera. Si no, evalúa "partes" por sí mismo: que también evalúa como "verdadero" en ruby ​​(cualquier objeto que no sea nil se considera "verdadero" para propósitos de lógica booleana ")

Cuestiones relacionadas