2016-12-23 51 views
4

我知道有在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) 

但它是一個語法錯誤。那麼發生了什麼?

+1

許多Rubiests,包括我自己在內,*不要*使用'和'或'或'。用'&&'和'||'堅持會簡化你的生活,而不會限制你的選擇。 –

回答

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] 
+0

已更新。對不起,我的第一個回答是錯誤的。「提出」某事「比'或'具有更高的優先級,儘管我找不到任何有關它的官方聲明。 –

+0

這是因爲'raise'是一個方法調用。它是'Kernel'模塊中定義的全局函數之一,因此與任何方法調用具有相同的語法和優先級。 – akuhn

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 

相當於(粉飾布爾和邏輯之間,或者現在因爲你的例子,無論如何處理布爾值的差異)

p(foo = false.|(true)) 

因此當執行打印true並返回true

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

同樣的答案爲2個不同的問題,您管理錯過兩個點!你不解釋SyntaxError。 '||'不等同於方法調用,因爲它們根本沒有相同的優先級,而且'A || B'也可以看作'如果A然後A別的B結束'。 –

+0

你說得對,他們實際上產生了相同的字節碼。從概念上講,雖然其中一個意味着像方法一樣的操作符,而另一個意味着控制流。我可以解釋語法錯誤......哦,你在你的答案! – akuhn