Ruby3.3リファレンスマニュアルで主要なクラスだけ調べた。
経緯
昨日の「勝手にモブプロ」で、Rubyにも===
あるよねって話が出てた。
そうだっけ?なにするんだっけ?って思ったので調べた。
結論
Objectクラスで===
は定義されている。デフォルトはObjectクラスの==
と同じ。
==
と===
は、各クラスの性質に合わせて各クラスで再定義されている。
===
が==
と異なる意味で再定義されている主要なクラス↓
・Range
・Regexp
・Proc
・Module
case when式
のwhen
は===
を呼び出している。
詳細
Objectクラスの == と ===
根本的なところ
==
Object#== (Ruby 3.3 リファレンスマニュアル)
オブジェクトと other が等しければ真を返します。
デフォルトでは equal? と同じオブジェクトの同一性判定になっています。
つまりobject_idが等しければtrueを返す。
このメソッドは各クラスの性質に合わせて再定義すべきです。多くの場合、オブジェクトの内容が等しければ真を返すように(同値性を判定するように)再定義されることが期待されています。
この部分は下記のおまけに記載。
===
Object#=== (Ruby 3.3 リファレンスマニュアル)
デフォルトでは内部で Object#== を呼び出します。
==
と同じくobject_idが等しければtrueを返す。
case 式で使用されるメソッドです。制御構造/case も参照してください。
case式に関しては以下。
制御構造 (Ruby 3.3 リファレンスマニュアル)
case 式0 when 式1, 式2 stmt1 when 式3, 式4 stmt2 else stmt3 end
は以下とほぼ等価
_tmp = 式0 if 式1 === _tmp or 式2 === _tmp stmt1 elsif 式3 === _tmp or 式4 === _tmp stmt2 else stmt3 end
=== が ==と異なる再定義をしているもの
Range
Range#=== (Ruby 3.3 リファレンスマニュアル)
始端と終端のなかにあるときにtrueを返す。
内部ではRange#cover?
が実行されている。
(2.5以前はRange#include?だった)
(1..10) === 10 #=> true (1...10) === 10 #=> false ("a".."b").include?("a") #=> true ("a".."b").include?("ab") #=> false ("a".."b").cover?("ab") #=> true ("a".."b") === "ab" #=> true
Regexp
Regexp#=== (Ruby 3.3 リファレンスマニュアル)
文字列との正規表現マッチを行う。マッチしたときはtrueを返す。
/\A[a-z]*\z/ === "HELLO" #=> false /\A[A-Z]*\z/ === "HELLO" #=> true "HELLO" === /\A[A-Z]*\z/ #=> false #逆はダメなので注意
Proc
Proc#=== (Ruby 3.3 リファレンスマニュアル)
Procオブジェクトを実行して結果を返す。
proc = Proc.new{ | a , b | a * b } proc.call(2, 5) #=> 10 proc[2, 5] #=> 10 proc === [2, 5] #=> 10
Module
Module#=== (Ruby 3.3 リファレンスマニュアル)
指定のオブジェクトがそのクラスかそのサブクラスのインスタンスであるときtrueを返す。
class Mikan < Object end class Arita < Mikan end mikan = Mikan.new arita = Arita.new Object === mikan #=> true Mikan === mikan #=> true Arita === mikan #=> false Object === arita #=> true Mikan === arita #=> true Arita === arita #=> true mikan === Mikan #=> false #逆はダメなので注意
おまけ
== は 人の目で同じならtrue、に再定義がほとんどっぽい
たしかにequal?
と==
がちょっと意味が違うクラスがほとんど。
人の目でみて同じならtrue、という意味に再定義されている。
Integer
Integer#== (Ruby 3.3 リファレンスマニュアル)
1 == 2 #=> false 1 == 1.0 #=> true 1.equal?(1.0) #=> false
1
はIntegerクラスで1.0
はFloatクラスだが、==
はtrueになる
Array
Array#== (Ruby 3.3 リファレンスマニュアル)
array = [ "a", "c", 7 ] array == [ "a", "c" ] #=> false array == [ "a", "c", 7 ] #=> true array.equal?([ "a", "c", 7 ]) #=> false
Hash
Hash#== (Ruby 3.3 リファレンスマニュアル)
hash = { 1 => :a, 2 => :b } hash == { 1 => :a } #=> false hash == { 2 => :b , 1 => :a } #=> true hash == { 2 => :b , 1.0 => :a } #=> false { :x => 1 } == { :x => 1.0 } #=> true
Range
Range#== (Ruby 3.3 リファレンスマニュアル)
range = (1..2) range == (1..2) #=> true range == (1...2) #=> false (1..2) == Range.new(1.0, 2.0) #=> true range.equal?(1..2) #=> false
Regexp
Regexp#== (Ruby 3.3 リファレンスマニュアル)
a = /\d\d\d/ a == /\d\d\d/ #=> true a == /\d{3}/ #=> false a.equal?(/\d\d\d/) #=> false
終わりに
るりま読んでこれ書いたけど、チェリー本にがっつり書いてあった…。
===
がどのように定義されているか分かるとwhen
節の条件部に何を書くか明確にできる。(気がする)
完全未経験から現在フィヨルドブートキャンプで学習中。
自分で気になったところの記録(メモ)です。
間違い等あればご指摘いただければ幸いです。