Understanding the “||” OR operator in If conditionals in Ruby

后端 未结 9 1396
再見小時候
再見小時候 2020-11-28 07:40

Just briefly, why are the following three lines not identical in their impact?

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


        
相关标签:
9条回答
  • 2020-11-28 07:53

    Basically, == doesn't distribute over other operators. The reason 3 * (2+1) is the same as 3 * 2 + 3 * 1 is that multiplication distributes over addition.

    The value of a || expression will be one of its arguments. Thus the 2nd statement is equivalent to:

    if @controller.controller_name == "projects"
    

    || is of lower precedence than ==, so the 3rd statement is equivalent to:

    if (@controller.controller_name == "projects") || "ports"
    
    0 讨论(0)
  • 2020-11-28 07:56

    The simple way to get a non verbose solution is

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

    This actually has nothing to do with ||, but rather what values are considered to be true in ruby. Everything save false and nil is true.

    0 讨论(0)
  • 2020-11-28 07:57

    || is also a null coalescing operator, so

    "projects" || "parts"
    

    will return the first string that is not null (in this case "projects"), meaning that in the second two examples, you'll always be evaluating:

    if @controller.controller_name == "projects"
    

    Firing up irb, you can check that this is happening:

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

    returns projects

    0 讨论(0)
  • 2020-11-28 07:58

    The logical or operator || works on boolean expressions, so using it on strings doesn't do what you want.

    There are several ways to achieve what you want that are less verbose and more readable.

    Using Array#include? and a simple if-statement:

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

    Using a case-statement:

    case @controller.controller_name
    when "projects", "parts" then
      do_something
    else
      do_something_else
    end
    
    0 讨论(0)
  • 2020-11-28 08:00

    The difference is the order of what's happening. Also the || isn't doing what you think it does in the 2 and 3.

    You can also do

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

    to reduce code in the future if you need to add more matches.

    0 讨论(0)
  • 2020-11-28 08:09

    the exact semantics of || are:

    • if first expression is not nil or false, return it
    • if first expression is nil or false, return the second expression

    so what your first expression works out to is, if @controller.controller_name == "projects", then the expression short-circuits and returns true. if not, it checks the second expression. the second and third variants are essentially if @controller.controller_name == "projects", since "projects" || "parts" equals "projects". you can try this in irb:

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

    what you want to do is

    if ["projects", "parts"].include? @controller.controller_name
    
    0 讨论(0)
提交回复
热议问题