一段邏輯複雜的程式碼,可能包含了很多的算符(operator)
,這些算符孰先孰後是有個先後順序的,就像小學四則運算人人會背的口訣先乘除,後加減
如果不了解,容易有意想不到的 bug 產生。
考考大家
下面的 today 是幾號?
today = '25號' || '26號' && '27號'
today # => ?
答案是 "25號"
還不懂優先級的我,會認為是"27號"
原本我是這麼想:
1.首先"25號"
先跟"26號"
用||
運算子來判斷,因為第一個"25號"
就是true
,所以回傳"25號"
。
2.然後"25號"
跟"27號"
用&&
運算子來判斷,兩個都是true
所以回傳第二個"27號"
。
(以上是錯的)
(以下才是對的)
因為&&
的優先序比||
高
所以是先判斷'26號' && '27號'
,回傳"27號"
。
再判斷'25號' || '27號'
,就回傳'25號'
Ruby這麼多算符,誰先誰後?
下面這個表都整理好了,越上面,優先級越高
看完上圖可以觀察到一個邏輯
四則運算
> 比大小
> 是否相等
> 邏輯且/或
> 三元
> 賦值
在我們公司的legency code(譯:活化石code),還看到前人會使用and
跟 or
,但是新code就完全沒人用了,而且裝上Rubocop後,還出現警告。
看過前面那張表後,就不難理解為什麼 Rubocop 會建議:
&&
取代and
||
取代or
因為 &&
跟 and
雖然中文意思都是且
,但是兩個的優先序不相等,造成and
跟or
可能有意想不到的bug
舉例說明,定義方法second_present?
來判斷是否有第二本漫畫,有的話就回傳第二本的書名。然後在方法裡面用@result
接住結果,我預期@result
跟second_present?
回傳的結果是一樣的
def second_present?(comic1 = nil, comic2 = nil)
@result = comic1 and comic2
end
second_present?('海賊王', '租借女友' ) # => "租借女友"
@result # => "海賊王"
second_present?('海賊王') # => nil
@result # => "海賊王"
沒想到@result
出乎我意料之外,@result
不只沒有回傳第二本書名,而且不管有沒有第二本,都只回傳第一本的書名。
這就是and
的雷,因為and
的優先序在=
後面。
上面這段code如果把and
改用&&
就能呈現我所希望的結果。
自己操作一次就知道了