今天來分享 Ruby 裡的 ==
, ===
, eql?
, equal?
。
物件相等與內容等同性
有時,特別是在物件導向編程中,對資料型別和繼承物件進行比對時,出現了相等性和辨別的問題。以下情況通常需要區別:
- 相同型別的兩個不同物件,例如兩隻手
- 兩個物件相等但不同,例如兩張 10 元鈔票
- 兩個物件相等但有不同的呈現,例如 $1 元紙鈔和 $1 元硬幣
-- 維基百科
==
:最常使用,比較雙方的值如果相等,回傳 true。eql?
:如果接收者和参数具有相同的類型和相等的值,回傳 true。我們試著來比較兩者的不同:
a = "abc" # 印出 "abc"
b = a + "" # 印出 "abc"
a == b # 印出 true
a.eql?(b) # 印出 true
c = 1.0 # 印出 1.0
d = 1 # 印出 1
c == d # 印出 true
c.eql?(d) # 印出 false
從以上例子看到 1 與 1.0 同樣皆為數值 1 ,但 eql?
除了比較直是否相等,還需比較類型,則 1 的類別為 Integer
,1.0 的類別為 Float
。
===
:用於比較 case 语句的 when 是否相等記得之前我們在「流程控制與條件判斷」篇有分享 case..when
,這個方法的比較正是使用 ===
,我們來舉個例子:
def calc_sum(param)
if param.class == Array
param.sum
elsif param.class == Integer
param
else
0
end
end
puts calc_sum([1, 2, 3, 4, 5]) # 印出 15
puts calc_sum(5) # 印出 5
puts calc_sum(nil) # 印出 0
也許你會發現 case..when
其實是 if..else
加上 ===
的語法糖,可以更口語化的使用你的程式語言是 Ruby 的賣點之一。
def calc_sum(param)
if Array === param
param.sum
elsif Integer === param
param
else
0
end
end
def calc_sum(param)
case param
when Array
param.sum
when Integer
param
else
0
end
end
這裡需要注意幾件事:
1+1
時,其實是 1.+(1)
。[1,2] === Array
與 Array === [1,2]
會得到不同結果,你可以將之想像成 Array.===([1,2,3])
才是他真實的樣子。正規表示式
中有提到 "Regexp" 這個類別,也是用 ===
來實作。我們一一來舉例:
[1,2,3] === Array # 印出 false
Array === [1,2,3] # 印出 true
[1,2,3].is_a?(Array) # 印出 true
/cu/ === "cute" # 印出 true
/\w/ === "cute" # 印出 true
"cute" === /\w/ # 印出 false
相同object_id
,是則回傳 true。a_string = "string"
another_string = "string"
a_string.equal?(another_string) # 印出 false
a_string = :string
another_string = :string
a_string.equal?(another_string) # 印出 true
a = "string".freeze
b = "string".frezze
a.equal?(b) # 印出 true
還記得 symbol
與 字串
的比較嗎? 同名的 symbol 只會有一個,它只佔了一塊記憶體的位置,因此會有相同的 object_id
,你可以試試 freeze
這個方法,你會發現某種程度它同時擁有兩者的優點,這或許是 Ruby 未來的版本宣稱要將字串預設為冷凍狀態的原因!
此文同步刊登於CJ-Han的網站