iT邦幫忙

第 11 屆 iThome 鐵人賽

DAY 27
0
Software Development

Ruby 研究 30 天系列 第 27

Day 26 - == , === , eql? , equal?

  • 分享至 

  • twitterImage
  •  

今天來分享 Ruby 裡的 == , === , eql? , equal?

物件相等與內容等同性

有時,特別是在物件導向編程中,對資料型別和繼承物件進行比對時,出現了相等性和辨別的問題。以下情況通常需要區別:

  • 相同型別的兩個不同物件,例如兩隻手
  • 兩個物件相等但不同,例如兩張 10 元鈔票
  • 兩個物件相等但有不同的呈現,例如 $1 元紙鈔和 $1 元硬幣
    -- 維基百科

== 與 eql?

  • == :最常使用,比較雙方的值如果相等,回傳 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. 首先,在 Ruby 裡,左側運算元是訊息的接收者,右側則是方法呼叫的引數,這意味著等號左右不一定能交換,像是當你在寫 1+1 時,其實是 1.+(1)
  2. 因此,當你問 Ruby [1,2] === ArrayArray === [1,2] 會得到不同結果,你可以將之想像成 Array.===([1,2,3]) 才是他真實的樣子。
  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

equal?

  • 比較接收者和參数是否具有 相同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的網站


上一篇
Day 25 - 正規表示式
下一篇
Day 27 - 例外處理
系列文
Ruby 研究 30 天30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言