https://mauricio.github.io/2011/05/30/ruby-basics-equality-operators-ruby.html
Ruby has a lot of equality operators, some of which are everywhere in our application (such as the common double equal sign - "=="), and some may not be as common (such as the third equal sign - "===") Now let's dig deeper into how Ruby compares objects.
Perhaps because of my past Java experience, I think it makes sense to define what is "equal" first. Objects in Ruby have their identifiers, which can be calledobject_idThe method is easy to view.
some_string = 'some string'
=> "some string"
another_string = 'another_string'
=> "another_string"
[ some_string.object_id, another_string.object_id ]
=> [2164900860, 2164888440]
As you continue to create new objects, Ruby assigns object_id to each object, which you can use to distinguish between objects.
matz = 'matz'
=> "matz"
matz_2 = 'matz'
=> "matz"
[ matz.object_id, matz_2.object_id ]
=> [2164840660, 2164818480]
The values of the above two objects are exactly the same, but they have different object_ids, so Ruby does not think that the two values are the same. Object_id can be thought of as a shortcut to identify objects, and each object can be compared to other objects.
Two strings representing the same character should be equal, and two people with the same ID number should be the same person. Programming languages must provide the means to achieve this level of comparison, which are these equal methods in Ruby.
The double equal sign method should implement the object's universal identification algorithm. This usually means comparing object properties, not whether they are the same object in memory. Since Ruby is a dynamically typed language, don't rely too much on types. You should rely on methods. Don't judge whether an object is from a class, but check if it can respond to a specific method:
class Meter
def initialize( value )
@value = value
end
def to_meters
@value.to_f
end
def ==( other )
if other.respond_to?( :to_meters )
self.to_meters == other.to_meters
end
end
end
First verify that the object has a method that you expect to use instead of verifying its type, then compare the two objects. If 'false' is returned, the two objects are not equal.
If you have implemented the "==" method, you should also implement the "eql?" and "hash" methods, even if you have never seen where these methods have been called. Because if your object is used as a hash key, these are the methods used by the hash object to compare with your object. The hash needs to quickly determine if the key already exists, so avoid comparing each individual object. by usinghashThe return value of the method classifies the objects into groups and then uses them in batches.eql?Contrast objects.
When searching for key values in a hash, first call the keyhashMethod to determine which group it belongs to, then useeql?Compare with other objects in the same group. Even in the worst case, we only need to compare with three objects (the hash has nine objects), which is acceptable. But if we use arrays, we need to make 9 comparisons in the worst case.
Give an example:
class StringWithoutHash
def initialize(text)
@text = text
end
def to_text
@text
end
def ==(other_value)
if other_value.respond_to?(:to_text)
self.to_text == other_value.to_text
end
end
end
The "==" method has been implemented correctly, but "hash" and "eql?" have not been implemented yet. So in the hash it is not possible to judge that they belong to the same type (will not be assigned to the same group for comparison).
context 'without hash and eql? methods' do
it 'should be equal' do
@first = StringWithoutHash.new('first')
@second = StringWithoutHash.new('first')
@first.should == @second
end
it 'should add as two different keys in the hash' do
@texts = {}
10.times do
@texts[ StringWithoutHash.new('first') ] = 'one'
end
@texts.keys.size.should == 10
end
end
Even though @firsh and @second represent exactly the same value, since we didn't implement the "hash" and "eql?" methods, we still generate two keys instead of one in the hash. The general practice is to overload "hash" and "eql?" if you override the "==" method. A basic rule when implementing "hash" is that if two objects are "==", then they should generate the exact same hash value (which can be found in the hash object), but with the same hash value. The two objects are still different (they belong to the same group but do not belong to the same object).
Correct implementation in the following exampleeql?withhashThe StringWithHash of the method is a subclass of StringWithoutHash (eql?Method can be used directly==, we don't even have to write code for it)
class StringWithHash < StringWithoutHash
def eql?( other )
self == other
end
def hash
@text.hash
end
end
The corresponding test code is as follows:
context 'with hash and eql? methods' do
it 'should be equal' do
@first = StringWithHash.new('first')
@second = StringWithHash.new('first')
@first.should == @second
end
it 'should add as a single key in the hash' do
@texts = {}
50.times do
@texts[ StringWithHash.new('first') ] = 'one'
end
@texts.keys.size.should == 1
end
end
Because we implemented it correctlyeql?with hashThe method, even if you add 50 objects to the hash, the number of hashes is still 1.
Unless you know what you are doing (and understand how hashes are implemented in Ruby), don't try to implement them yourself.hashMethod, just likeNumberwithStringAs the class does, use it directlyBasicObjectmiddlehashThe method is just fine. The following example:
class Meter
# all the other methods
def hash
self.to_meters.hash
end
def eql?( other )
self == other
end
end
Here, myhashThe method is called directlyFloatofhash. If there is no special need, you can completely copy my implementation here.
The third sign is an interesting operator that is scattered throughout the Ruby source code, but most developers rarely see it in actual development. Why is this so? Because it is hidden in a common control structurecase/whenin. When usedcase/whenWhen it is actually in use===Operator. It is also===The operator makes Ruby's case condition more powerful than C or Java.
Take a look at the following example:
age = 19
case age
when 1..18
puts 'just out of college'
when 19..30
puts 'wild years'
when 31..40
puts 'i better find a job in a big corp'
else
puts 'retirement plan'
end
This code will be called===And print out 'wild years'. See how it works? The following isifVersion implementation:
if 1..18 === age
puts 'just out of college'
elsif 19..30 === age
puts 'wild years'
elsif 31..40 === age
puts 'i better find a job in a big corp'
else
puts 'retirement plan'
end
In general,case/whenThe statement is simply simplified and beautified===withifThe operation of a statement combination. For the language itself, the third equal sign is used more as a "grouping" operation. The grouping is determined by passing in a value.
Usually, we use the keyword def to define the method. But when there are a series of methods with the same structure and logic, continuing to do so seems a bit repetitive and violates the DRY principl...
Equal operators with no access to the accessories == Logic equal operator === The same operation operation If the number of two operations is different, the compatible operator will be expanded to the...
The introduction of an interesting question When you use "==", have you found it? This A and B are obviously not equal. How does it perform the content of the cycle body! strangeness? For ex...
The reason is because nil is a fixed object. The ruby.h header file in $rubyhome\lib\1.8\i386-mswin32 has the following special object structure. In the active support of rails, there is...
== equal value Eql? values are equal, type is equal Equal? equal values, equal memory addresses ...
Transfer from: Like other OO languages, in ruby, the function of the object is completed by sending a message to the object, such as str.upcase , which is to send the upcase message to str, the dot op...
Original source:Object Equality in JavaScript Equality is the most confusing part of JavaScript at first.==with===The comparison, the order of the mandatory types, and so on, complicate the problem. T...
Ruby's sentence structure: 1: Variable 2: Comment 3: embedded documents 4: Reserved Words Ruby current implementation uses the ASCII character set. Uppercase and lowercase letters can be recognized. I...
program: 1: formula (that is, lines of code, huh, huh) 2: terminate the program Program is a formula composed of side by side. Use a semicolon or newline to distinguish between expression and expressi...