为什么写或不是||?

时间:2016-12-23 23:44:37

标签: ruby operators

我知道another answer中显示的优先级有所不同:

p foo = false || true
# => true

p foo = false or true
# => false

但似乎or||之间存在更多不同之处。

例如:

p foo = 42 or raise "Something went wrong with foo"
# => 42
p foo = nil or raise "Something went wrong with foo"
# => Something went wrong with foo (RuntimeError)
p foo = 42 || raise "Something went wrong with foo"
# => syntax error, unexpected tOP_ASGN, expecting end-of-input

我期待得到:

p foo = 42 or raise "Something went wrong with foo"
# => 42
p foo = nil or raise "Something went wrong with foo"
# => Something went wrong with foo (RuntimeError)
p foo = 42 || raise "Something went wrong with foo"
# => Something went wrong with foo (RuntimeError)

但这是一个语法错误。那么发生了什么?

2 个答案:

答案 0 :(得分:8)

理论:

这是Ruby的precedence table

从此表中不清楚,但没有括号的Ruby方法调用的优先级低于||=,但高于or。请参阅此question

因此,对于您的代码,从最高优先级到最低优先级:

  • ||
  • =
  • raise "something"
  • or

or

的表达式
foo = 42 or raise "Something went wrong with foo"

首先是=

( foo = 42 ) or raise "Something went wrong with foo"

然后raise

( foo = 42 ) or ( raise "Something went wrong with foo" )

然后or

( ( foo = 42 ) or ( raise "Something went wrong with foo" ) )

||

的表达式
foo = 42 || raise "Something went wrong with foo"

首先是||

foo = ( 42 || raise ) "Something went wrong with foo"

这是您的语法错误!

你想:

foo = 42 || (raise "Something went wrong with foo") #=> 42

foo = 42 || raise("Something went wrong with foo")  #=> 42

或只是

foo = 42 || raise 

警告!

当您遇到优先事项时,应该小心添加另一个putsp而不加括号!

例如:

p [1,2,3].map do |i|
  i*2
end

输出:

#<Enumerator: [1, 2, 3]:map>

即使您可能已经预料到:

[2, 4, 6]

答案 1 :(得分:1)

||or的操作不同。

第一个相当于方法调用,后者是控制流关键字。您可能总是希望使用||来避免与优先级混淆。由于这个原因,Ruby的大多数样式指南都有一个禁止使用andor的条款。

那么,

A or B

# can be considered equivalent to

if A then A else B end

,而

A || B

# can be considered equivalent to

A.or { B } # given a hypothetical "logical or" method

现在让我们看一下你的or示例

p foo = false or true

相当于

temp = p(foo = false) # => nil
if temp
  temp
else
  true
end

因此在执行时会打印false并返回true

[1] pry(main)> p foo = false or true
false
=> true
[2] pry(main)> foo
=> false

p foo = false || true

等同于(现在掩盖了布尔值和逻辑OR之间的差异,因为你的例子无论如何都在处理布尔值)

p(foo = false.|(true))

因此在执行时会打印true并返回true

[1] pry(main)> p foo = false || true
true
=> true
[2] pry(main)> foo
=> true