これら4つの方法の違いを理解しようとしています。デフォルトでは、==
がequal?
メソッドを呼び出すことを知っています。これは、両方のオペランドがまったく同じオブジェクトを参照している場合にtrueを返します。
デフォルトでは、===
も==
..を呼び出すequal?
を呼び出します。それで、これら3つのメソッドすべてがオーバーライドされないのであれば、===
、==
およびequal?
はまったく同じです。
今eql?
が来ます。これは何をするのでしょうか(デフォルト)。オペランドのハッシュ/ IDを呼び出しますか?
なぜRubyはそれほど多くの等号を持っているのですか?それらはセマンティクスが異なるはずですか?
私はそれがいくつかの素晴らしい説明を持っていると思うので、私は重く引用するつもりです オブジェクトドキュメンテーション ここ。 String のように他のクラスでオーバーライドされているので、それを読み、またこれらのメソッドのドキュメントを読むことをお勧めします。
補足:あなたがさまざまなオブジェクトに自分で試してみたい場合は、次のようなものを使用してください。
class Object
def all_equals(o)
ops = [:==, :===, :eql?, :equal?]
Hash[ops.map(&:to_s).Zip(ops.map {|s| send(s, o) })]
end
end
"a".all_equals "a" # => {"=="=>true, "==="=>true, "eql?"=>true, "equal?"=>false}
==
- 一般的な「平等」オブジェクトレベルでは、
obj
とother
が同じオブジェクトである場合に限り、==
はtrueを返します。通常、このメソッドは下位クラスでオーバーライドされてクラス固有の意味を提供します。
これは最も一般的な比較なので、2つのオブジェクトが「等しい」かどうかを(クラスの作成者として)判断する最も基本的な場所です。
===
- 大文字小文字の同一性Objectクラスの場合、事実上
#==
を呼び出すのと同じですが、caseステートメントで意味のあるセマンティクスを提供するために通常は下位クラスによってオーバーライドされます。
これは非常に便利です。興味深い===
実装を持つものの例:
だからあなたは以下のようなことをすることができます:
case some_object
when /a regex/
# The regex matches
when 2..4
# some_object is in the range 2..4
when lambda {|x| some_crazy_custom_predicate }
# the lambda returned true
end
case
+ Regex
がコードを非常にきれいにする方法の良い例については、 ここに私の答え を見てください。そしてもちろん、あなた自身の===
実装を提供することによって、あなたはカスタムのcase
セマンティクスを得ることができます。
eql?
- Hash
の同等性
obj
とother
が同じハッシュキーを参照している場合、eql?
メソッドはtrueを返します。これはHash
によってメンバーが等しいかどうかをテストするために使われます。 クラスObject
のオブジェクトの場合、eql?
は==
と同義です。 サブクラスは通常、eql?
をオーバーライドされた==
メソッドにエイリアスすることでこの伝統を継続しますが、例外があります。たとえば、Numeric
型は、==
全体で型変換を実行しますが、eql?
全体では変換しません。1 == 1.0 #=> true 1.eql? 1.0 #=> false
それであなたはあなた自身の使用のためにこれを自由にオーバーライドすることができます、あるいはあなたは==
をオーバーライドしそしてalias :eql? :==
を使うことができますので2つのメソッドは同じように振る舞います。
equal?
- アイデンティティ比較
==
とは異なり、equal?
メソッドはサブクラスによってオーバーライドされるべきではありません。つまり、オブジェクトの同一性を判断するために使用されます(つまり、a.equal?(b)
iffa
がb
と同じオブジェクトである)。
これは実質的にポインタ比較です。
私はjtbandesの回答が大好きですが、それはかなり長いので、私は自分自身のコンパクトな回答を追加します。
==
、===
、eql?
、equal?
は4つのコンパレータです。 Rubyで2つのオブジェクトを比較する4つの方法。
Rubyでは、すべてのコンパレータ(およびほとんどの演算子)は実際にはメソッド呼び出しであるため、これらの比較メソッドのセマンティクスを自分で変更、上書き、および定義できます。しかし、Rubyの内部言語構造がどのコンパレータを使用するかを理解することは重要です。
==
(値比較)
Rubyは2つのオブジェクトの 値 を比較するためにどこでも:==を使っています。ハッシュ値
{a: 'z'} == {a: 'Z'} # => false
{a: 1} == {a: 1.0} # => true
===
(ケース比較)
Rubyはcase/whenの構成要素に:===を使います。次のコードスニペットは論理的に同じです。
case foo
when bar; p 'do something'
end
if bar === foo
p 'do something'
end
eql?
(ハッシュキー比較)
Rubyはeql?を使っています。ハッシュキーを比較する(メソッドhashと組み合わせて)。ほとんどのクラスでは:eql? ==と同じです。
に関する知識:eql?あなたがあなた自身の特別なクラスを作りたいときにだけ、重要です。
class Equ
attr_accessor :val
alias_method :initialize, :val=
def hash() self.val % 2 end
def eql?(other) self.hash == other.hash end
end
h = {Equ.new(3) => 3, Equ.new(8) => 8, Equ.new(15) => 15} #3 entries, but 2 are :eql?
h.size # => 2
h[Equ.new(27)] # => 15
注意:一般的に使われているRubyクラスセットはハッシュキー比較にも依存しています。
equal?
(オブジェクト識別情報の比較)
Rubyは使っている:等しい? 2つのオブジェクトが同一かどうかを確認します。このメソッド(BasicObjectクラスの)は上書きされません。
obj = obj2 = 'a'
obj.equal? obj2 # => true
obj.equal? obj.dup # => false
==演算子は、等価性または二重等価性とも呼ばれ、両方のオブジェクトが等しい場合はtrueを返し、等しくない場合はfalseを返します。
"koan" == "koan" # Output: => true
!=演算子は、不等式とも呼ばれ、==の逆です。両方のオブジェクトが等しくない場合はtrueを返し、等しい場合はfalseを返します。
"koan" != "discursive thought" # Output: => true
順序が異なる同じ要素を持つ2つの配列は等しくなく、大文字と小文字の同じ文字は等しくないなどです。
異なる型の数(整数と浮動小数点数など)を比較するとき、それらの数値が同じであれば、==はtrueを返します。
2 == 2.0 # Output: => true
両方のオペランドが等しいかどうかをテストする==演算子とは異なり、equalメソッドは2つのオペランドが同じオブジェクトを参照しているかどうかを確認します。これはRubyでの最も厳密な等価形式です。
例:a = "zen" b = "zen"
a.object_id # Output: => 20139460
b.object_id # Output :=> 19972120
a.equal? b # Output: => false
上記の例では、同じ値を持つ2つの文字列があります。ただし、それらは異なるオブジェクトIDを持つ2つの異なるオブジェクトです。したがって、等しい?メソッドはfalseを返します。
もう一度試してみましょう。今度はbだけがaへの参照になります。オブジェクトIDは両方の変数で同じであることに注意してください。これらは同じオブジェクトを指すためです。
a = "zen"
b = a
a.object_id # Output: => 18637360
b.object_id # Output: => 18637360
a.equal? b # Output: => true
Hashクラスでは、eql?メソッドが等しいかどうかキーをテストするために使用されます。これを説明するには、ある程度の背景が必要です。コンピューティングの一般的な文脈では、ハッシュ関数は任意のサイズの文字列(またはファイル)を受け取り、ハッシュコードと呼ばれる固定サイズの文字列または整数を生成します。通常、これはハッシュのみと呼ばれます。一般的に使用されるハッシュコードの種類には、MD5、SHA-1、およびCRCがあります。これらは、暗号化アルゴリズム、データベースのインデックス作成、ファイルの整合性チェックなどに使用されます。Rubyなどの一部のプログラミング言語では、ハッシュテーブルと呼ばれるコレクション型が提供されています。ハッシュテーブルは、一意のキーとそれに対応する値からなるペアでデータを格納する辞書風のコレクションです。内部では、これらのキーはハッシュコードとして保存されています。ハッシュテーブルは通常、単にハッシュと呼ばれます。 Wordのハッシュがハッシュコードまたはハッシュテーブルをどのように参照するかに注意してください。 Rubyプログラミングの文脈では、Wordハッシュはほとんどの場合、辞書に似たコレクションを指します。
Rubyはハッシュコードを生成するためにhashと呼ばれる組み込みメソッドを提供します。以下の例では、文字列を受け取り、ハッシュコードを返します。たとえ別のオブジェクトであっても(異なるオブジェクトIDを持つ)、同じ値を持つ文字列が常に同じハッシュコードを持つことに注意してください。
"meditation".hash # Output: => 1396080688894079547
"meditation".hash # Output: => 1396080688894079547
"meditation".hash # Output: => 1396080688894079547
ハッシュメソッドは、すべてのRubyオブジェクトのデフォルトルートであるObjectクラスに含まれるKernelモジュールに実装されています。 SymbolやIntegerなどの一部のクラスはデフォルトの実装を使用し、StringやHashなどの他のクラスは独自の実装を提供します。
Symbol.instance_method(:hash).owner # Output: => Kernel
Integer.instance_method(:hash).owner # Output: => Kernel
String.instance_method(:hash).owner # Output: => String
Hash.instance_method(:hash).owner # Output: => Hash
Rubyでは、ハッシュ(コレクション)に何かを保存すると、キーとして提供されたオブジェクト(例えば文字列やシンボル)はハッシュコードに変換されて保存されます。後で、ハッシュ(コレクション)から要素を取得するときに、オブジェクトをキーとして提供し、それをハッシュコードに変換して既存のキーと比較します。一致するものがあれば、対応する項目の値が返されます。比較は、EQLを使用して行われますか?フードの下の方法。
"zen".eql? "zen" # Output: => true
# is the same as
"zen".hash == "zen".hash # Output: => true
ほとんどの場合、EQL? methodは==メソッドと同じように動作します。ただし、いくつか例外があります。たとえば、eqlの?整数とfloatを比較するとき、暗黙的に型変換は行われません。
2 == 2.0 # Output: => true
2.eql? 2.0 # Output: => false
2.hash == 2.0.hash # Output: => false
String、Range、RegexpなどのRubyの組み込みクラスの多くは、独自の===演算子の実装を提供します。これらは、大文字小文字の区別、三重等号または三重等号とも呼ばれます。各クラスで実装が異なるため、呼び出されたオブジェクトの種類によって動作が異なります。一般に、右側のオブジェクトが左側のオブジェクトの「に属している」または「のメンバー」である場合はtrueを返します。たとえば、オブジェクトがクラスのインスタンス(またはそのサブクラスの1つ)であるかどうかをテストするために使用できます。
String === "zen" # Output: => true
Range === (1..2) # Output: => true
Array === [1,2,3] # Output: => true
Integer === 2 # Output: => true
その仕事におそらく最も適している他の方法でも同じ結果が得られる。効率性や簡潔さを犠牲にすることなく、できるだけ明示的に記述することで読みやすいコードを書くのが一般的です。
2.is_a? Integer # Output: => true
2.kind_of? Integer # Output: => true
2.instance_of? Integer # Output: => false
2などの整数は、IntegerクラスのサブクラスであるFixnumクラスのインスタンスであるため、最後の例ではfalseが返されています。 ===、is_a?そしてinstance_of?オブジェクトが指定されたクラスまたは任意のサブクラスのインスタンスである場合、メソッドはtrueを返します。 instance_ofメソッドはより厳密で、オブジェクトがサブクラスではなくその正確なクラスのインスタンスである場合にのみtrueを返します。
Is_a?そしてkind_of?メソッドは、Kernelモジュールに実装されています。これは、Objectクラスによって組み込まれています。どちらも同じメソッドのエイリアスです。確認しましょう:
Kernel.instance_method(:kind_of?)== Kernel.instance_method(:is_a?)#出力:=> true
範囲オブジェクトに対して===演算子が呼び出されると、右側の値が左側の範囲内にある場合にtrueが返されます。
(1..4) === 3 # Output: => true
(1..4) === 2.345 # Output: => true
(1..4) === 6 # Output: => false
("a".."d") === "c" # Output: => true
("a".."d") === "e" # Output: => false
===演算子は左側のオブジェクトの===メソッドを呼び出すことを忘れないでください。つまり、(1..4)=== 3は(1..4)と等価です。=== 3.言い換えれば、左辺のオペランドのクラスは、===メソッドのどの実装を定義するのかを定義します。オペランド位置は互換性がありません。
右側の文字列が左側の正規表現と一致する場合、trueを返します。/zen/=== "今日のzazen練習"#出力:=> true#は "今日のzazen練習"と同じ= =/zen /
この演算子はcase/whenステートメントの裏でも使われています。それが最も一般的な使い方です。
minutes = 15
case minutes
when 10..20
puts "match"
else
puts "no match"
end
# Output: match
上記の例では、Rubyが暗黙的に二重等価演算子(==)を使用していた場合、10..20の範囲は15のような整数と等しいとは見なされません。すべてのcase/whenステートメントで暗黙的に使用されています。上記の例のコードは、以下と同等です。
if (10..20) === minutes
puts "match"
else
puts "no match"
end
=〜(equal-tilde)および!〜(bang-tilde)演算子は、文字列とシンボルを正規表現パターンと照合するために使用されます。
StringクラスとSymbolクラスの=〜メソッドの実装では、引数として正規表現(Regexpクラスのインスタンス)が必要です。
"practice zazen" =~ /zen/ # Output: => 11
"practice zazen" =~ /discursive thought/ # Output: => nil
:zazen =~ /zen/ # Output: => 2
:zazen =~ /discursive thought/ # Output: => nil
Regexpクラスの実装は引数として文字列またはシンボルを期待します。
/zen/ =~ "practice zazen" # Output: => 11
/zen/ =~ "discursive thought" # Output: => nil
すべての実装で、文字列またはシンボルがRegexpパターンと一致すると、一致の位置(インデックス)である整数を返します。一致しない場合は、nilを返します。 Rubyでは、任意の整数値が "truthy"、nilが "falsy"なので、=〜演算子はif文と3項演算子で使用できます。
puts "yes" if "zazen" =~ /zen/ # Output: => yes
"zazen" =~ /zen/?"yes":"no" # Output: => yes
パターンマッチング演算子は、if文を短く書くのにも役立ちます。例:
if meditation_type == "zazen" || meditation_type == "shikantaza" || meditation_type == "kinhin"
true
end
Can be rewritten as:
if meditation_type =~ /^(zazen|shikantaza|kinhin)$/
true
end
!〜演算子は=〜の逆で、一致がない場合はtrueを返し、一致がある場合はfalseを返します。
より詳しい情報は このブログ記事 で入手可能です。
私は===
演算子を拡張したいと思います。
===
は等価演算子ではありません。
違います。
その点を本当によく理解しましょう。
===
をJavascriptとPHPの等価演算子として使い慣れているかもしれませんが、これはRubyの等価演算子ではなく、基本的に異なる意味を持ちます。
それで===
は何をしますか?
===
はパターンマッチング演算子です。
===
は正規表現に一致します===
は範囲のメンバーシップをチェックします===
はクラスのインスタンスであることをチェックします===
はラムダ式を呼び出します===
は平等をチェックすることがありますが、ほとんどはそうではありませんでは、この狂気はどのように意味があるのでしょうか。
Enumerable#grep
は内部的に===
を使用しますcase when
ステートメントは内部的に===
を使用しますrescue
は内部的に===
を使用していますcase when
ステートメントで正規表現、クラス、範囲そしてラムダ式さえも使用できるのはそのためです。
いくつかの例
case value
when /regexp/
# value matches this regexp
when 4..10
# value is in range
when MyClass
# value is an instance of class
when ->(value) { ... }
# lambda expression returns true
when a, b, c, d
# value matches one of a through d with `===`
when *array
# value matches an element in array with `===`
when x
# values is equal to x unless x is one of the above
end
これらすべての例は、grep
メソッドと同様にpattern === value
でも動作します。
arr = ['the', 'quick', 'brown', 'fox', 1, 1, 2, 3, 5, 8, 13]
arr.grep(/[qx]/)
# => ["quick", "fox"]
arr.grep(4..10)
# => [5, 8]
arr.grep(String)
# => ["the", "quick", "brown", "fox"]
arr.grep(1)
# => [1, 1]
どちらも似たような働きをしますが、 "==="でもcase文を実行します。
"test" == "test" #=> true
"test" === "test" #=> true
ここで違い
String === "test" #=> true
String == "test" #=> false
Rubyは同等性を扱うためのいくつかの異なるメソッドを公開しています。
a.equal?(b) # object identity - a and b refer to the same object
a.eql?(b) # object equivalence - a and b have the same value
a == b # object equivalence - a and b have the same value with type conversion.
下のリンクをクリックして読み続けてください、それは私に明確な要約された理解を与えました。
https://www.relishapp.com/rspec/rspec-expectations/v/2-0/docs/matchers/equality-matchers
それが他の人に役立つことを願っています。