Comprensione dell’operatore “||” OR in If condizionali in Ruby

Solo brevemente, perché le seguenti tre righe non sono identiche nel loro impatto?

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 poiché ci sono in realtà più opzioni che solo progetti e parti, l’uso di quel modulo crea un’istruzione prolissa. Gli altri due sono più compatti, ma non mi danno lo stesso risultato.

la semantica esatta di || siamo:

  • se la prima espressione non è nul o falsa, restituiscila
  • se la prima espressione è nul o false, restituisce la seconda espressione

quindi, a cosa serve la prima espressione, 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" "projects" || "parts" uguale a "projects" . puoi provarlo in irb:

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

quello che vuoi fare è

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

La differenza è l’ordine di ciò che sta accadendo. Anche il || non sta facendo quello che pensi che faccia nel 2 e 3.

Puoi anche fare

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

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

|| è anche un operatore a coalescenza nulla, quindi

 "projects" || "parts" 

restituirà la prima stringa che non è nulla (in questo caso “progetti”), il che significa che nei secondi due esempi, starai sempre valutando:

 if @controller.controller_name == "projects" 

Firing up irb, puoi verificare che ciò stia accadendo:

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

restituisce projects

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

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

 if @controller.controller_name == "projects" 

|| ha una precedenza più bassa di ==, quindi la 3a affermazione è equivalente a:

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

Ci sono alcune cose diverse in corso lì:

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

questo dà il comportamento che vuoi sto assumendo. La logica è piuttosto semplice: restituisce true se il nome del controler è “project” o “parts”

Un altro modo per farlo è:

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

Questo controllerà se il nome del controller è da qualche parte nella lista.

Ora per gli altri esempi:

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

Questo non farà quello che vuoi. Valuterà ("projects" || "parts") primo (il che si tradurrà in “progetti”), e 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 object non nullo è considerato “vero” ai fini della logica booleana “)

Il modo 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 quali valori sono considerati veri nel ruby. Tutto ciò che è falso e nullo è vero.

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

Ci sono diversi modi per ottenere quello che vuoi che siano meno prolissi e più leggibili.

Usare l’array # include? e una semplice dichiarazione if:

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

Utilizzando una dichiarazione di un caso:

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

La prima confronta i letterali stringa “projects” e “parts” con la variabile @controller.controller_name .

Il secondo valuta (“progetti” || “parti”) che è “progetti” perché “progetti” stringa letterale né falsenil o stringa vuota e lo confronta con @controller.controller_name

Il terzo confronta @controller.controller_name e “projects” e se sono uguali, restituisce true , se non lo sono restituisce “parts” che è uguale a true per if statement.