Ruby の文字列比較 [eql?, equal?, ==, ===] の使い分けを汗臭く説明 #ruby

# Ruby の文字列比較 `[eql?, equal?, ==, ===]` の使い分けを:sweat_drops::sweat_drops:汗臭く:sweat_drops::sweat_drops:説明します
## :musical_score: 概要
Ruby の文字列比較 `[eql?, equal?, ==, ===]` の使い分け ( :see_no_evil::hear_no_evil::speak_no_evil: ) について

:rage::feelsgood::rage::feelsgood::rage::feelsgood:
:feelsgood::sweat_drops::sweat::disappointed_relieved::cold_sweat::rage:
:rage::sweat::disappointed_relieved::cold_sweat::sweat_drops::feelsgood:
:feelsgood::disappointed_relieved::cold_sweat::sweat_drops::sweat::rage:
:rage::cold_sweat::sweat_drops::sweat::disappointed_relieved::feelsgood:
:rage::feelsgood::rage::feelsgood::rage::feelsgood:

汗臭い成分はここまで。

## :hand: 内容を読む前に
又その話かよ :rage1: と思ったあなた。
はい、その話です。

すでに理解している方は特に読む意味がない記事です。
自分が未だに、この部分を覚えていなくて

:worried::question:「 あれ？ eql? と equal? ってどっちがどっちだっけ？」

と、都度検索しているので、
1 回自分でまとめ直したいと思いました。

## <i class="fa fa-cubes" style="font-size:1em;"></i> 同値性
### <i class="fa fa-image" style="font-size:1em;"></i> Images
:neckbeard::id:1 :o: :neckbeard::id:2
:neckbeard::id:1 :o: :neckbeard::id:1
:neckbeard::id:1 :x: :smiley::id:3
### <i class="fa fa-cube" style="font-size:1em;"></i> `eql?`
`String#eql?` は、同値性の比較を行う。
文字列の内容が等しければ別のオブジェクトでも true を返却する。

~~~ruby
hoge = 'hoge'
puts hoge.eql?(hoge) # => true
puts hoge.eql?('hoge') # => true
~~~

Hash のクラス内での比較に使われる。

~~~ruby
hash = {}
hash[hoge] = 'test'
puts hash[hoge] # => test
puts hash['hoge'] # => test
~~~

### <i class="fa fa-cube" style="font-size:1em;"></i> `==`
`String#==(other)` も `String#eql?` と同様に同値性の比較を行う。
ただし、 other が String 以外だった場合、

* `other#to_str` があれば、 `other == self` で比較
* それ以外は false を返却

する点が異なる。

~~~ruby
hoge = 'hoge'
puts hoge == (hoge) # => true
puts hoge == ('hoge') # => true

hash = {}
hash[hoge] = 'test'
puts hash[hoge] # => test
puts hash['hoge'] # => test

class Age
  def initialize(age)
    @age = age
  end

  def to_str
    @age.to_s
  end

  def ==(other)
    self.to_str == other
  end
end

puts '20'.eql?(Age.new(20)) # => false
puts '20' == Age.new(20) # => true
~~~

### <i class="fa fa-cube" style="font-size:1em;"></i> `===`
`String#===(other)` の機能面は `String#==(other)` と同じ。

用途の違いがあり、
`String#===(other)`  は case 文で暗黙的に使用されている。

~~~ruby
def test
  %w(hoge hige hage hoo).each do |text|
    ret = case text
    when 'hoge' then 'ほげ'
    when 'hige' then 'ひげ'
    when 'hage' then 'はげ'
    else text
    end
    puts ret
  end
end

test

class String
  # override して、呼びだされていることを確認
  def ===(other)
    puts "**#{other}**"
  end
end

test
~~~

* 出力

~~~
ほげ
ひげ
はげ
hoo
**hoge**
**hoge**
**hoge**
hoge
**hige**
**hige**
**hige**
hige
**hage**
**hage**
**hage**
hage
**hoo**
**hoo**
**hoo**
hoo
~~~

## <i class="fa fa-cubes" style="font-size:1em;"></i> 同一性
### <i class="fa fa-image" style="font-size:1em;"></i> Images
:neckbeard::id:1 :x: :neckbeard::id:2
:neckbeard::id:1 :o: :neckbeard::id:1
:neckbeard::id:1 :x: :smiley::id:3
### <i class="fa fa-cube" style="font-size:1em;"></i> `equal?`
内部的には <i class="fa fa-external-link" style="font-size:1em;"></i>[Object#equal?](http://docs.ruby-lang.org/ja/2.2.0/method/Object/i/equal=3f.html) が呼び出されています。

`Object#equal?` は同一性をチェックします。
内部的には `Object#object_id` を比較しています。
同じ文字列でも、同一のオブジェクトでなければ false になります。

~~~ruby
hoge1 = 'hoge'
hoge2 = 'hoge'

puts hoge1.object_id # => 12887137880
puts hoge2.object_id # => 12887137860

puts hoge1.equal?(hoge2) # => false
puts hoge1.equal?(hoge1) # => true
~~~

## 使い分け表

|Method|同値性|同一性|他オブジェクトの比較|case 文|
|:--|:--:|:--:|:--:|:--:|
|eql?|:o:|:x:|:x:|:x:|
|==|:o:|:x:|:o:|:x:|
|===|:o:|:x:|:o:|:o:|
|equal?|:x:|:o:|:x:|:x:|

## :books: 外部資料
* <i class="fa fa-external-link" style="font-size:1em;"></i> [るりま | Object#equal?](http://docs.ruby-lang.org/ja/2.2.0/method/Object/i/equal=3f.html)
* <i class="fa fa-external-link" style="font-size:1em;"></i> [るりま | String#eql?](http://docs.ruby-lang.org/ja/2.2.0/method/String/i/eql=3f.html)
* <i class="fa fa-external-link" style="font-size:1em;"></i> [るりま | String#==, ===](http://docs.ruby-lang.org/ja/2.2.0/method/String/i/=3d=3d.html)