为什么“真实或真实与错误”似乎同时存在真假?

我得到以下内容:

puts true or true and false # >> true 

而我也得到:

 if true or true and false puts "that's true!" else puts "that's false!" end # >> that's false! 

为什么true or true and false都是false (如薛定谔的猫)?

它与优先权有关。 puts true or true and false实际计算为(puts true) or (true and false) [编辑:不完全。 请参阅下面Todd的注释。]if true or true and false计算为if (true or (true and false)) 。 这是由于puts (方法)和if (语言关键字)相对于表达式的其他项的优先级。

当你评估puts true or true and false时,你会在irb中看到=> false (记住,那是(puts true) or (true and false) )因为puts输出为true并返回nil ,这是假的,导致(true and false)接下来要评估,返回false

这是大多数Ruby指南推荐使用&&||原因之一 代替andor在布尔表达式中。 puts true || true && false puts true || true && false计算为puts (true || (true && false))if true || true && false if true || true && false计算结果如同if (true || (true && false)) ,正如您所期望的那样。

优先权

Ruby的解析器依赖于优先级表 。 在您的示例中, or具有比and更高的优先级。 另外,如果第一个表达式是真实的,则短路评估不会评估条件的第二项。

另请注意,在Ruby 内核中,puts是一个采用可选参数的方法,而if是一个词法标记。 虽然许多人在惯用Ruby中省略了括号,但优先级可以改变解析器在评估复杂或模糊表达式(如true or true and false时所看到的内容。 正如您将在下面看到的,条件和方法之间的区别使问题进一步复杂化。

通常,应该将表达式括起来以避免歧义,并尽可能少地依赖运算符优先级。 总有例外,尤其是像Ruby这样的富有表现力的语言,但作为经验法则,它可以极大地简化Rubyist的生活。

检查解析器

如果您对解析器看到的内容一直存在疑问,则不必单独依赖推理。 您可以使用Ripper模块检查符号表达式树。 例如:

 require 'pp' require 'ripper' pp Ripper.sexp 'true or true and false' 

这将告诉你:

 [:program, [[:binary, [:binary, [:var_ref, [:@kw, "true", [1, 0]]], :or, [:var_ref, [:@kw, "true", [1, 8]]]], :and, [:var_ref, [:@kw, "false", [1, 17]]]]]] 

这表明解析器认为表达式本身就会将其括号化为(true or true) and false

同样,if语句具有相同的优先级:

 pp Ripper.sexp 'if true or true and false; end' 
 [:program, [[:if, [:binary, [:binary, [:var_ref, [:@kw, "true", [1, 3]]], :or, [:var_ref, [:@kw, "true", [1, 11]]]], :and, [:var_ref, [:@kw, "false", [1, 20]]]], [[:void_stmt]], nil]]] 

但是,因为puts是一种方法,所以它的解析方式不同:

 pp Ripper.sexp 'puts true or true and false' 
 [:program, [[:binary, [:binary, [:command, [:@ident, "puts", [1, 0]], [:args_add_block, [[:var_ref, [:@kw, "true", [1, 5]]]], false]], :or, [:var_ref, [:@kw, "true", [1, 13]]]], :and, [:var_ref, [:@kw, "false", [1, 22]]]]]] 

换句话说,解析器假设您的模糊语句大致等同于以下带括号的表达式: (puts(true) or true) and (false) 。 在这种情况下,假设第一个true是Kernel#puts的参数。 由于puts方法总是返回nil (这是假的),然后评估第二个true ,使得put puts(true) or true truthy。 接下来,计算终端表达式并返回false ,而不管puts-statement是否将true输出到标准输出。

这里有两件事。

评估

 if true or true and false puts "that's true!" else puts "that's false!" end 

true or true and false计算结果为false。 这就是为什么that's false! 输出。

优先权

or优先级低于|| 。 这可能会造成混乱的情况,因为设置的值与正在评估的值不同。 例如:

 a = false || true => true puts a true a = false or true => true puts a false 

在第二个示例中, 评估true ,但优先级将a设置为false 。 我希望这有帮助,我发现这个资源非常有用。

这是我第二次尝试总结我的理解,每个人都对我的问题做出了很好的回应。 对工程师和Joseph Cho的特别呐喊。 几次读完你的答案后,灯泡继续亮着。

puts false or true && true输出false并返回true

puts false || true and false puts false || true and false输出为true并返回nil

在这种情况下,优先顺序是

  1. &&
  2. ||
  3. 看跌期权
  4. 和,或

    puts false or true && true变为puts false or true 。 第一部分, puts false输出false并返回nil 。 该语句现在为nil or true ,返回true

同样, puts false || true and false puts false || true and false变得puts true and false 。 然后第一部分puts true输出设为true并返回nil 。 这些陈述现在nil and false ,将返回nil