= = 对比 = = 在 Ruby 中

在 Ruby 中,= = 和 = = 之间的区别是什么

对于类对象, 实际上等同于调用 # = = , 但通常被 提供有意义的 案例陈述中的语义。

#==是否与 ==相同? 你能否举例说明在案例陈述中何时/如何使用 #==

24548 次浏览

Yes, by #== the docs mean "the instance method == of the current object".

=== is used in case statements as such:

case obj
when x
foo
when y
bar
end

Is the same as

if x === obj
foo
elsif y === obj
bar
end

Some classes that define their own === are Range (to act like include?), Class (to act like obj.is_a?(klass)) and Regexp (to act like =~ except returning a boolean). Some classes that don't define their own === are the numeric classes and String.

So

case x
when 0
puts "Lots"
when Numeric
puts(100.0 / x)
when /^\d+$/
puts(100.0 / x.to_f)
default
raise ArgumentError, "x is not a number or numeric string"
end

is the same as

if 0 == x
puts "Lots"
elsif x.is_a? Numeric
puts(100.0 / x)
elsif x =~ /^\d+$/
puts(100.0 / x.to_f)
else
raise ArgumentError, "x is not a number or numeric string"
end

The two really have nothing to do with each other. In particular, #== is the equality operator and #=== has absolutely nothing to with equality. Personally, I find it rather unfortunate that #=== looks so similar to #==, uses the equals sign and is often called the case equality operator, triple equals operator or threequals operator when it really has nothing to do with equality.

I call #=== the case subsumption operator (it's the best I could come up with, I'm open to suggestions, especially from native English speakers).

The best way to describe a === b is "if I have a drawer labeled a, does it make sense to put b in it?"

So, for example, Module#=== tests whether b.is_a?(a). If you have Integer === 2, does it make sense to put 2 in a box labeled Integer? Yes, it does. What about Integer === 'hello'? Obviously not.

Another example is Regexp#===. It tests for a match. Does it make sense to put 'hello' in a box labeled /el+/? Yes, it does.

For collections such as ranges, Range#=== is defined as a membership test: it makes sense to put an element in a box labeled with a collection if that element is in the collection.

So, that's what #=== does: it tests whether the argument can be subsumed under the receiver.

What does that have to with case expressions? Simple:

case foo
when bar
baz
end

is the same as

if bar === foo
baz
end

Fun fact, === is also used to match exceptions in rescue

Here is an example

class Example
def self.===(exception)
puts "Triple equals has been called."
true
end
end


raise rescue Example
# => prints "Triple equals has been called."
# => no exception raised

This is used to match system errors.

SystemCallError.=== has been defined to return true when the two have the same errno. With this system call errors with the same error number, such as Errno::EAGAIN and Errno::EWOULDBLOCK, can both be rescued by listing just one of them.