新手会遇到平等方法的问题:
-
a == b :检查 a 和 b 是否相等。这是最有用的。
-
a.eql? b :还检查 a 和 b 是否相等,但有时更严格(例如,它可能检查 a 和 b 是否具有相同的类型)。主要用于Hashes。
-
a.等于? b :检查 a 和 b 是否是同一个对象(身份检查)。
-
a === b :用于 case 语句(我将其理解为“a 匹配 b”)。
这些示例应该阐明前 3 种方法:
a = b = "joe"
a==b # true
a.eql? b # true
a.equal? b # true (a.object_id == b.object_id)
a = "joe"
b = "joe"
a==b # true
a.eql? b # true
a.equal? b # false (a.object_id != b.object_id)
a = 1
b = 1.0
a==b # true
a.eql? b # false (a.class != b.class)
a.equal? b # false
注意 ==、eql? 和 equal? 应该始终是对称的:如果 a==b 那么 b==a。
还要注意 == 和 eql? 都在 Object 类中作为 equal? 的别名实现,所以如果你创建一个新的类并希望 == 和 eql? 意味着除了普通身份之外的其他内容,那么您需要覆盖它们。例如:
class Person
attr_reader name
def == (rhs)
rhs.name == self.name # compare person by their name
end
def eql? (rhs)
self == rhs
end
# never override the equal? method!
end
=== 方法的行为不同。首先它是 not 对称的(a===b 确实 not 暗示 b===a )。正如我所说,您可以将 a===b 解读为“a 匹配 b”。以下是几个例子:
# === is usually simply an alias for ==
"joe" === "joe" # true
"joe" === "bob" # false
# but ranges match any value they include
(1..10) === 5 # true
(1..10) === 19 # false
(1..10) === (1..10) # false (the range does not include itself)
# arrays just match equal arrays, but they do not match included values!
[1,2,3] === [1,2,3] # true
[1,2,3] === 2 # false
# classes match their instances and instances of derived classes
String === "joe" # true
String === 1.5 # false (1.5 is not a String)
String === String # false (the String class is not itself a String)
case 语句基于 === 方法:
case a
when "joe": puts "1"
when 1.0 : puts "2"
when (1..10), (15..20): puts "3"
else puts "4"
end
等价于:
if "joe" === a
puts "1"
elsif 1.0 === a
puts "2"
elsif (1..10) === a || (15..20) === a
puts "3"
else
puts "4"
end
如果你定义一个新类,它的实例代表某种容器或范围(如果它有类似 include? 或 match? 方法),那么你可能会发现像这样覆盖 === 方法很有用:
class Subnet
[...]
def include? (ip_address_or_subnet)
[...]
end
def === (rhs)
self.include? rhs
end
end
case destination_ip
when white_listed_subnet: puts "the ip belongs to the white-listed subnet"
when black_listed_subnet: puts "the ip belongs to the black-listed subnet"
[...]
end