2009-10-12 4 views
20

Juste brièvement, pourquoi les trois lignes suivantes ne sont pas identiques dans leur impact?Comprendre le "||" Opérateur OR dans Si conditions dans Ruby

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

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

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

Le premier me donne le résultat que je veux, mais comme il y a en fait plus d'options que seulement des projets et des pièces, en utilisant ce formulaire crée une déclaration verbeux. Les deux autres sont plus compacts, mais ne me donnent pas le même résultat.

Répondre

38

la sémantique exacte de || sont:

  • si la première expression est non nul ou faux, le retourner
  • si la première expression est nulle ou faux, retourner la deuxième expression

donc ce que votre première expression fonctionne à est, si @controller.controller_name == "projects", l'expression court-circuite et renvoie true. sinon, il vérifie la seconde expression. les deuxième et troisième variantes sont essentiellement if @controller.controller_name == "projects", puisque "projects" || "parts" est égal à "projects". vous pouvez essayer cela en irb:

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

ce que vous voulez faire est

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

|| est également un opérateur coalescent nul, si

"projects" || "parts" 

retournera la première chaîne qui est non nulle (dans ce cas, les « projets »), ce qui signifie que dans le second deux exemples, vous aurez toujours évaluerons:

if @controller.controller_name == "projects" 

mise à feu jusqu'à RIR, vous pouvez vérifier que cela se passe:

a = "projects" 
b = "parts" 

a || b 

renvoie projects

+4

en fait,' ou' deux chaînes ensemble vous donnera la première chaîne, pour soutenir les idiomes comme 'a || =" bonjour "' et 'a = somefunc() || default' –

+0

Vous avez absolument raison, j'ai mis à jour ma réponse. – jerhinesmith

6

La différence est de l'ordre de ce qui se passe. Aussi le || ne fait pas ce que vous pensez qu'il fait dans le 2 et 3.

Vous pouvez également faire

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

pour réduire le code à l'avenir si vous avez besoin d'ajouter plus de matches.

2

La façon simple d'obtenir une solution non bavard est

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

Cela n'a en fait rien à voir avec ||, mais quelles valeurs sont considérées comme vrai rubis. Tout sauvera faux et nul est vrai.

0

La première compare les littéraux de chaîne "projets" et "parties" à la variable @controller.controller_name.

deuxième (« projets evalue » || « parties ») qui est « projets » parce que « les projets » chaîne littérale ni false ou nil ou une chaîne vide et le comparer à @controller.controller_name

Troisième on compare @controller.controller_name et " projets "et si elles sont égales, il renvoie true, si ce n'est pas le cas, il retourne" parts "qui est égal à true pour if déclaration.

1

L'opérateur logique ou || fonctionne sur les expressions booléennes, donc en utilisant il sur les chaînes ne fait pas ce que vous voulez.

Il existe plusieurs façons d'obtenir ce que vous voulez qui sont moins verbeux et plus lisibles.

En utilisant Array # include? et un simple instruction if:

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

l'aide d'un cas déclaration:

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

Fondamentalement, == ne distribue pas sur d'autres opérateurs. La raison 3 * (2+1) est la même que 3 * 2 + 3 * 1 est que la multiplication distribue sur l'addition.

La valeur d'un || l'expression sera l'un de ses arguments. Ainsi, la deuxième déclaration est équivalente à:

if @controller.controller_name == "projects" 

|| est inférieure precedence que ==, donc la 3ème déclaration équivaut à:

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

Il y a quelques différentes choses qui se passent là-bas:

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

cela donne le comportement que vous voulez je suppose. La logique est assez basique: return true si le nom de controleur est soit « projets » ou « parties »

Une autre façon de le faire est:

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

qui vérifiera si le nom du contrôleur est quelque part dans le liste.

Maintenant, pour les autres exemples:

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

Ce ne sera pas ce que vous voulez. Il évaluera d'abord ("projects" || "parts") (ce qui aboutira à des "projets"), puis ne vérifiera que si le nom du contrôleur est égal à cela.

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

Celui-ci devient encore plus fou. Cela aboutira toujours à vrai. Il vérifie d'abord si le nom du contrôleur est égal à "projets". Si c'est le cas, l'instruction est vraie. Sinon, il évalue lui-même "parts": qui évalue aussi "true" dans ruby ​​(tout objet non nul est considéré comme "vrai" pour les besoins de la logique booléenne ")

Questions connexes