Entender el operador “||” O en If conditionals en Ruby

Solo brevemente, ¿por qué las siguientes tres líneas no son idénticas en su impacto?

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

El primero me da el resultado que quiero, pero como en realidad hay más opciones que solo proyectos y partes, el uso de ese formulario crea una statement detallada. Los otros dos son más compactos, pero no me dan el mismo resultado.

la semántica exacta de || son:

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

Entonces, ¿cuál es tu primera expresión? Si @controller.controller_name == "projects" , la expresión cortocircuita y devuelve true . si no, verifica la segunda expresión. la segunda y la tercera variantes son esencialmente if @controller.controller_name == "projects" , ya que "projects" || "parts" "projects" || "parts" es igual a "projects" . puedes probar esto en irb:

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

lo que quieres hacer es

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

La diferencia es el orden de lo que está sucediendo. También el || no está haciendo lo que crees que hace en el 2 y 3.

También puedes hacer

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

para reducir el código en el futuro si necesita agregar más coincidencias.

|| es también un operador coalescente nulo, entonces

 "projects" || "parts" 

devolverá la primera cadena que no sea nula (en este caso “proyectos”), lo que significa que en los segundos dos ejemplos, siempre estará evaluando:

 if @controller.controller_name == "projects" 

Encendiendo IRB, puedes verificar que esto esté sucediendo:

 a = "projects" b = "parts" a || b 

devuelve projects

Básicamente, == no se distribuye sobre otros operadores. La razón por la que 3 * (2+1) es lo mismo que 3 * 2 + 3 * 1 es que la multiplicación se distribuye sobre la sum.

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

 if @controller.controller_name == "projects" 

|| es de menor precedencia que ==, por lo que la tercera statement es equivalente a:

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

Hay algunas cosas diferentes pasando allí:

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

esto te da el comportamiento que quieres, estoy asumiendo. La lógica es bastante básica: devuelve verdadero si el nombre del controlador es “proyectos” o “partes”

Otra forma de hacer esto es:

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

Eso verificará si el nombre del controlador está en alguna parte de la lista.

Ahora para los otros ejemplos:

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

Esto no hará lo que quieras. 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 se pone aún más loco. Esto siempre dará como resultado verdadero. Primero comprobará si el nombre del controlador es igual a “proyectos”. Si es así, la statement se evalúa como verdadera. Si no, evalúa “partes” por sí mismo: que también se evalúa como “verdadero” en ruby ​​(cualquier objeto que no sea nil se considera “verdadero” a los efectos de la lógica booleana “)

La forma simple de obtener una solución no detallada es

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

Esto en realidad no tiene nada que ver con || , sino más bien qué valores se consideran verdaderos en ruby. Todo excepto falso y nada es verdad.

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

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

Usar Array # include? y una simple instrucción if:

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

Usando una statement de caso:

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

El primero compara los literales de cadenas de “proyectos” y “partes” con la variable @controller.controller_name .

El segundo evalúa (“projects” || “parts”) que es “projects” porque “projects” string literal ni false o nil o cadena vacía y lo compara con @controller.controller_name

El tercero compara @controller.controller_name y “projects” y si son iguales, devuelve true , si no lo son devuelve “parts”, que es igual a true para if statement.