关于ruby:’case’语句如何与常量一起使用?

How does the 'case' statement work with constants?

我正在使用Ruby1.9.2和RubyonRails3.2.2。我有以下方法:

1
2
3
4
5
6
7
8
9
# Note: The 'class_name' parameter is a constant; that is, it is a model class name.
def my_method(class_name)
  case class_name
  when Article then make_a_thing
  when Comment then make_another_thing
  when ...     then ...    
  else raise("Wrong #{class_name}!")
  end  
end

我想知道为什么在上面的case语句中,当我执行诸如my_method(Article)my_method(Comment)等方法调用时,它总是运行else部分。

我如何解决这个问题?有人建议如何处理这件事吗?


这是因为case调用===,类(或特定的模块,哪个类的下位)上的===是这样实现的:

mod === objtrue or false

Case Equality—Returns true if obj is an instance of mod or one of mod’s descendants. Of limited use for modules, but can be used in case statements to classify objects by class.

这意味着,对于除ClassModule以外的任何常数(例如FooFoo === Foo总是返回false。因此,在您的case语句中,您总是得到else条件。

相反,只需使用对象本身而不是其类来调用case,或者使用if语句。


将对象引用传递给方法,就像在后台一样,它使用==运算符,因此这些操作将失败。例如

1
2
3
4
5
6
7
8
9
obj = 'hello'
case obj.class
when String
  print('It is a string')
when Fixnum
  print('It is a number')
else
  print('It is not a string')
end

另一方面,这样做很好:

1
2
3
4
5
6
7
8
9
obj = 'hello'
case obj  # was case obj.class
when String
  print('It is a string')
when Fixnum
  print('It is a number')
else
  print('It is not a string')
end

请参阅"如何在Ruby中编写switch语句"的相关答案https://stackoverflow.com/a/5694333/1092644


如果只想比较名称的相等性,可以将to_s添加到类常量中。

1
2
3
4
5
6
7
8
9
10
11
def my_method(class_name)
  case class_name.to_s
  when 'Article'
    make_a_thing
  when 'Comment'
    make_another_thing

  ... ...

  end  
end