【Ruby】case比較演算子(===)の挙動

zomです。 Rubyを始めてもう少しで1年になりますが、まだまだ知らないことだらけで 今日もまた新しい発見があったので書いておきます。

Rubyではcase比較演算子というものがあります。 それが===です。 PHPでは型もチェックする厳密な比較という意味でしたが、Rubyでは扱いが違います。 Rubyではクラスのチェックに使うことが主です。

data = 'hoge'
case data
when ::String
  p 'string'
when ::Hash
  p 'hash'
end
# => 'string'

Rubyでは上記のようにcase(PHPで言うところのswitch(※))でクラスの比較をすることができます。 'hoge'はStringクラスのインスタンスですので、Stringに属しているといってもいいかもしれません。 そのため::Stringにマッチしてp 'string'が実行されます。 このcaseの内部処理で使われているのが===ということです。

ですので、ifで書きなおせば以下のようになります。

data = 'hoge'
if ::String === data
  p 'string'
elsif ::Hash === data
  p 'hash'
end

では、ここで本題。

::String === 'hoge'
# => true
'hoge' === ::String
# => false

こんな実行結果になります。さて、なぜ順番を変えただけで実行結果が変わってしまうのでしょうか?

答えは、レシーバが違うことと、演算子メソッドであることかと思います。 レシーバとは、メソッドを呼ばれたオブジェクトのことで、ここでいうところの===の前に来るものです。 これでレシーバが異なることで===演算子(メソッド)の挙動も異なるということになります。

このケースを噛み砕いて言うと、人間は動物の一種であるが、動物は人間の一種ではない、というところでしょうか。

いやー、caseの実装をifに書き換えた際に、この現象にはまってしまい十数分、頭を捻っていましたが、 原因がわかったときはRubyすげぇ!となぜか感動してしまいました。よく考えて見れば普通のコトなんですけどね。 まだまだ勉強が足りませんな。

ちなみにcase比較演算子という呼び方はオライリーの「初めてのRuby」にて記載されていたので、使わせて頂きました。

PHPでいうところのswitchなんて書くと怒られそうですが、似て非なるものだということを下記のブログを見て知っておいてもらえると幸いです。 Rubyのcaseを〇〇(言語名)のswitch文だと思っている人たちにぼくから一言ガツンと申し上げたい 本当はこれくらい突っ込んだ内容を書いたほうが、読者のためにもなるんだろうなぁ…。