Ruby中的===和==有什么区别?

78
在Ruby中,==和===之间有什么区别? RDoc说:

Case Equality - 对于类Object来说,等同于调用#==,但通常被子类覆盖,以在case语句中提供有意义的语义。

#====是一样的吗?你能提供一个在case语句中使用它的例子吗?

我认为这里的最佳答案是https://dev59.com/22855IYBdhLWcg3wNxgM#4467823。 - mmike
3个回答

143
两者实际上没有任何关联。特别是,#== 是等于运算符,而#===与相等毫不相关。个人认为,#===看起来与#==非常相似,使用了等号,并经常被称为“case equality操作符”、“triple equals操作符”或“threequals操作符”,但它实际上与相等无关,这让我感到非常遗憾。
我称#===为“case subsumption操作符”(这是我能想到的最好的术语,如果有更好的建议,尤其是来自以英语为母语的人士,欢迎提出)。
最好的方法是将a === b描述为“如果我有一个标记为a的抽屉,把b放在里面是否合理?”
例如,Module#===检查是否b.is_a?(a)。如果您有Integer === 2,那么将2放入标记为Integer的盒子中是否合理?是的。那Integer === 'hello'呢?显然不是。
另一个例子是Regexp#===。它测试与正则表达式匹配。将'hello'放进标记为/el+/的盒子中是否合理?是的。
对于像范围这样的集合,Range#===定义为成员资格测试:如果元素在集合中,则将元素放入标记为集合的盒子中是有意义的。
那么,这与case表达式有什么关系呢?简单:
case foo
when bar
  baz
end

与...相同

if bar === foo
  baz
end

4
在Ruby 1.8和1.9.1中,Array#===没有定义为成员关系操作符,但是Range#===有定义。 - sepp2k
2
@sepp2k:你说得对。这就是我在没有先查看文档的情况下假设合理语义所得到的结果。 - Jörg W Mittag
15
如果我有一个标着“A”的抽屉,把“B”放进去是有意义的吗?这是个很棒的形象。 - tokland
1
从更著名的Typeful Programming论文中可以得知:“由于myVehicle:VehicleVehicle<:Object,我们有myVehicle:Object(这被称为包容规则)。因此,期望对象的函数将接受车辆”,“在这里,ColorPoint <: Point,因此任何处理点的程序也将通过包容性接受彩色点。”,“子类型化通过包容性增加了类型的灵活性,但是通过相同的机制可能会导致类型信息的丢失。”还有一条名为“包容性”的类型规则。最著名的Java…是Anchored Exception Declarations论文。 - Jörg W Mittag
1
程序员熟悉的文献中都包含这个词,其中最为 Ruby 程序员所熟知的是 Diamondback 论文,Scala 程序员所熟知的则是 DOT 论文,Scala 语言规范也使用了它,等等。 - Jörg W Mittag
显示剩余7条评论

11

是的,文档中的#==指的是“当前对象的实例方法==”。

===被用于如下case语句:

case obj
when x
  foo
when y
  bar
end

与......相同

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

一些类定义了它们自己的 === 方法,例如Range(用于像 include?一样操作),Class(用于像 obj.is_a?(klass) 一样操作)和 Regexp (用于像 =~ 一样操作,但返回一个布尔值)。而某些没有定义它们自己的 === 方法,例如数字类和字符串类。

因此,

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

是相同的意思

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

如果你在when语句中放置一个字符串,那么它是否类似于说case x; when string --> if "string" == x - the12
1
@the12 你是在问Ruby是否会自动添加标识符周围的引号还是打错了?无论如何,case x; when string等同于if string === x,如果string包含一个字符串,则等同于if string == x。同样,case x; when "string"等同于if "string" === xif "string" == x - sepp2k

5

有趣的事实是,=== 也用于在 rescue 中匹配异常。

这里是一个例子:

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

这用于匹配系统错误。

SystemCallError.=== 已被定义为当两个 errno 相同时返回 true。使用此方法,具有相同错误号的系统调用错误,例如 Errno::EAGAINErrno::EWOULDBLOCK,可以通过仅列出其中一个来进行救援。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接