2009-10-12 7 views
20

Solo brevemente, perché le seguenti tre linee non sono identiche nel loro impatto?Comprensione del "||" Operatore O in Se condizionali in Ruby

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

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

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

Il primo mi dà il risultato che voglio, ma come c'è in realtà più opzioni che solo i progetti e le parti, con quella forma crea una dichiarazione prolisso. Gli altri due sono più compatti, ma non mi danno lo stesso risultato.

risposta

38

la semantica esatta di || sono:

  • se prima espressione non è nullo o falso, restituirlo
  • se prima espressione è nullo o falsa, riportare la seconda espressione

così ciò che la vostra prima espressione funziona a è, se @controller.controller_name == "projects", l'espressione si interrompe e restituisce true. in caso contrario, controlla la seconda espressione. la seconda e la terza variante sono essenzialmente if @controller.controller_name == "projects", poiché "projects" || "parts" è uguale a "projects". Si può provare questo in IRB:

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

ciò che si vuole fare è

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

|| è anche un operatore null coalescenza, così

"projects" || "parts" 

restituirà la prima stringa che non è nullo (in questo caso "progetti"), il che significa che nei secondi due esempi, avrete sempre essere valutando:

if @controller.controller_name == "projects" 

di accensione irb, è possibile verificare che questo sta accadendo:

a = "projects" 
b = "parts" 

a || b 

restituisce projects

+4

in realtà,' o 'a due stringhe insieme darò la prima stringa, per supportare espressioni come 'a || =" ciao "' e 'a = somefunc() || default' –

+0

Hai assolutamente ragione. Ho aggiornato la mia risposta. – jerhinesmith

6

La differenza è l'ordine di ciò che accade. Anche il || non sta facendo quello che pensi lo fa in 2 e 3.

È anche possibile fare

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

per ridurre il codice in futuro, se è necessario aggiungere più partite.

2

Il modo più semplice per ottenere una soluzione non prolissa è

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

Questo in realtà non ha nulla a che fare con ||, ma piuttosto ciò che i valori sono considerati per essere vero in Ruby. Tutto ciò che è falso e nullo è vero.

0

Primo confronta i valori letterali stringa "progetti" e "parti" nella variabile @controller.controller_name.

seconda valuta ("progetti" || "parti"), che è "progetti", perché "progetti" stringa letterale né false o nil o una stringa vuota e confrontarlo con @controller.controller_name

Terzo si confrontano @controller.controller_name e " progetti "e se sono uguali, restituisce true, se non lo sono restituisce" parti "che è uguale a true per la dichiarazione if.

1

L'operatore logico o || funziona su espressioni booleane, quindi usare su stringhe non fa quello che vuoi.

Esistono diversi modi per ottenere ciò che si desidera meno dettagliato e più leggibile.

Utilizzo dell'array # include? e un'istruzione if-semplice:

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

utilizzo di una custodia-istruzione:

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

Fondamentalmente, == non significa distribuire su altri operatori. Il motivo 3 * (2+1) è lo stesso di 3 * 2 + 3 * 1 è che la moltiplicazione viene distribuita in aggiunta.

Il valore di || espressione sarà uno dei suoi argomenti. Quindi la seconda affermazione è equivalente a:

if @controller.controller_name == "projects" 

|| è inferiore rispetto precedence ==, quindi il 3 ° istruzione è equivalente a:

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

Ci sono un paio di cose diverse in corso lì:

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

questo dà il comportamento desiderato sto assumendo. La logica è piuttosto semplice: restituisce true se il nome controler è o "progetti" o "parti"

Un altro modo di fare questo è:

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

che controllerà se il nome del controller è da qualche parte nel elenco.

Ora per gli altri esempi:

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

Questo non fare quello che vuoi. Valuterà prima ("projects" || "parts") (che genererà "progetti"), quindi controllerà solo se il nome del controller è uguale a quello.

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

Questo diventa ancora più bizzarro. Ciò si tradurrà sempre in vero. Verificherà prima se il nome del controller è uguale a "progetti". Se è così, l'affermazione è vera. In caso contrario, valuta "parti" su se stesso: che valuta anche "vero" in ruby ​​(qualsiasi oggetto non nullo è considerato "vero" ai fini della logica booleana ")