Ruby面試精選30題 - Day23 Ruby的'==','===' 'eql?' 'equal?'

前幾天我們把焦點集中在True or False(判斷真假),今天來研究幾個比較是否相等的方法!在程式世界裡,真假相等都有更多元、更超乎想像的概念。如果是程式新手,可能會對這幾個看起來特別像的運算子:==, ===, eql?, equal?充滿黑人問號…???

趕快來看看今天的題目!


重點摘要:


Ruby經典面試題目 #23

  • 解釋Ruby裡的 ==, ===, eql?, equal。 Explain each of the following operators ==, ===, eql?, equal?`

有些方法比其他的方法更相等(Some are more equal than others)。這是怎麼回事?讓我們繼續看下去~

1. ==

== 檢查兩個運算子的是否相等 (check if the value of two operands are equal)

2. eql?

如果接收器和參數的類型都相等,則為true. ( checks if the value and type of two operands are the same ),

eql?與 == 比較

來比較一下==.eql?的用法:

100 == 100.0 #=> true
100.eql?(100.0) #=> false

從以上例子看到100100.0同樣皆為數值1,但1的類型為Fixnum1.0的類型為Float浮點數(包含小數點)。

3. ===

=== 測試case語法中、when子句內的相等性 (test equality within the when clause of a case statement)

舉個生活化的例子來描述case語法:

下週我要出遠門旅行,因此我規劃去超市裡購物,在旅行大背包裡放一些食物補給品。我想要以[第7天]學到的符號Symbol將food歸類:

 def type_of(food)
  case food
  when 'Apple'
    :fruit
  when 'Banana'
    :fruit
  when 'Chocolate'
    :sweet
  when 'Noodles'
    :meal
  when 'Chips'
    :junkfood
  else
    :unknown
  end
end

p type_of 'Chips' # => :junkfood

hmmm….被發現買洋芋片是垃圾食物了了!

=== 與 if else

===代表的是 case equality

以上的case...when,其實是從if...else加上===的語法改寫而來。

def type_of(food)
  if 'apple' === food
    :fruit
  elsif 'Chocolate' === food
    :sweet
  elsif 'Noodles' === food
    :meal
  elsif 'Chips' === food
    :junkfood
  else
    :unknown
  end

p type_of 'Nuts' # => :unknown

旅行時買一些腰果核桃補充能量,比洋芋片建康一些。XD

補充一下:Ruby的when後面可以放多個參數,讓程式更簡潔,因此我來放更多的食物OrangeBread進去旅行大背包:

 def type_of(food)
  case food
  when 'Apple', 'Banana', 'Orange'
    :fruit
  when 'Chocolate'
    :sweet
  when 'Noodles', 'Bread'
    :meal
  when 'Chips'
    :junkfood
  else
    :unknown
  end
end

p type_of 'Orange' # => :fruit

=== 不是 ==

從以上大背包放食物的例子我們可以發現,===比的是case equality in case statement(更近一步來說,比的是上層的類別物件class object),所以以下四條判斷式,會顯示為全部為真:

p Class  === Class
p Object === Object

p Class  === Object
p Object === Class

# all true. 萬物皆為物件!

比較tricky的部分是Fixnum,我發現到了如果將Fixnum擺在===(threequality)的右邊,結果為假:

p 1 === 1 # => true
p Fixnum === 1 # => true

p 1 === Fixnum # => false
p Fixnum === Fixnum # => false
#warning: constant ::Fixnum is deprecated

Ruby Gotchas這份slide説明:

A better name (IMHO, 以我的觀點來說) might be .describes?, or overload .includes?

這或許就是為什麼我們不能把拿來比較的參數放在左邊,而是右邊:)

===, == 與 Regular Expression

使用===的好處就是可以用正規表示式提取、比較更多符合我們需求的條件。從以上的結論我們發現要將正規表示式放左邊。參考Ruby Doc 關於Regexp方法下的Public Instance Methods這頁說明,我們可以分別用 ===== 了解各項舉例是否為真:

p /banana/ === 'banana' # => true
p /banana/ === /banana/ # => false

p /banana/ == 'banana' # => false
p /banana/ == /banana/ # => true

為何在上述banana的例子裡,/banana/ === 'banana'為真,而 /banana/ == 'banana' 為假呢?

Regexp#===是用來比對(match)字串是否包含/正規表示式/裡的字符號 (tests whether or not the argument matches the regular expression.)。而在此例子裡,'banana'字串的確包含banana這些字符號。

/banana/'banana'本身並不是同一個值,所以==結果為假。

4. equal?

equal? : 如果接收器和參數的物件id(記憶體位置)相同,則為true (compares if both operands refer to the same object i.e. have the same object id)

equal? 與 eql? 與 == 比較

最後我們來用Ruby is Awesome作為總結吧!


ruby = "awesome"
rails = "awesome"

p ruby == rails   # => true #ruby和rails都很awesome!

p ruby.eql? rails # => true
# ruby和rails不但都很awesome, 而且兩者的類型都是字串(string)!

p ruby.equal? rails # => false
#ruby和rails分別存在不同的記憶體位置,它們不是同一個物件
p ruby.object_id #70263932897220
p rails.object_id #70263932897160

超級比一比:

== (等於) === eql? equal?
檢查兩個運算子的值是否相等 測試case語法中的when子句相等性 (object class) 如果接收器和參數的值類型都相等,則為true 如果接收器和參數的object id相同,則為true

Ref: