啊,这样一个看似简单的问题。但真的吗?
这里Product 是某个类,比如:
Product = Class.new
自从
Product.new.class
#=> Product
您的案例陈述可以简化为
case Product
when Module
'this condition will always be true'
when Product
'i need this to be true, so it never happens'
end
回想一下case 语句使用方法=== 来确定要返回哪个对象,这意味着您的case 语句等效于
if Module === Product
'this condition will always be true'
elsif Product === Product
'i need this to be true, so it never happens'
end
让我们看看这两个逻辑表达式是如何计算的:
Module === Product #=> true
Product === Product #=> false
注意这是
的语法糖
Module.===(Product) #=> true
Product.===(Product) #=> false
检查文档以了解方法 Module#=== 的工作原理:如果 Product 是 Module 或 Module 的后代之一的实例,则返回 true。嗯,是吗?
Product.class #=> Class
Class.ancestors #=> [Class, Module, Object, Kernel, BasicObject]
是的!现在呢:
Product === Product
Product 有方法=== 吗?:
Product.methods.include?(:===)
#=> true
它是从哪里来的(毕竟我们没有定义它)?我们先来看看:
Product.ancestors
#=> [Product, Object, Kernel, BasicObject]
Object 有方法=== 吗?检查我们看到的文档:Object#===.1
所以Object#=== 被调用。对?让我们确认一下:
Product.method(:===).owner
#=> Module
哎呀!它来自Module(它既是一个模块又是一个类),而不是来自Object。正如我们在上面看到的,Product 是Class 的一个实例,Class 是Module 的一个子类。另请注意,这里=== 是Class(和Module)的实例方法2:
Class.instance_method(:===).owner
#=> Module
所以Product 陷入了困境。它应该使用Module#===,它的父类(Class) 提供的实例方法,它从Module 继承,还是应该使用Object#===,它从它的超类Object 继承?答案是前者优先。
这是 Ruby 的“对象模型”的核心。我将不再多说,但我希望我已经为读者提供了一些工具,他们可以使用它们来弄清楚发生了什么(例如,Object#method 和 Method#owner。
由于Product === Product 与Module == Product 一样使用Module#===,我们通过回答问题来确定前者是否返回true,“是Product 的一个实例Product 还是Product 之一的后代?”。产品没有后代并且
Product.class #=> Class,
所以答案是“否”,意思是Product === Product 返回false。
编辑:我发现我忘了实际回答标题中提出的问题。我认为这需要一个意见(所以不行),但我认为case 声明是自切片面包以来最伟大的事情。当需要使用=== 或== 将各种值与参考值(例如,变量的内容或方法返回的值)进行比较时,它们特别有用。例如(参见Fixnum#===,其中=== 等价于==——请注意文档中的错字Regexp#=== 和Range#===):
str =
case x
when 1 then 'cat'
when 2,3 then 'dog'
when (5..Float#INFINITY) then 'cow'
else 'pig'
end
result =
case obj
when String
...
when Array
...
end
case str
when /\d/
...
when /[a-z]/
...
end
不过,除此之外,我经常使用case statement 代替if..elsif..else..end,只是因为我认为它更整洁、更美观:
case
when time == 5pm
feed the dog
when day == Saturday
mow the lawn
...
end
1 其实这个方法对所有对象都可用,但不是一般的
调用,因为该方法也是为后代定义的。
2 为了彻底混淆,Class 还有一个三等号类方法:
Class.method(:===).owner #=> Module.