【问题标题】:Ruby class types and case statementsRuby 类类型和 case 语句
【发布时间】:2011-04-23 22:19:06
【问题描述】:

有什么区别

case item.class
when MyClass
  # do something here
when Array
  # do something different here
when String
  # do a third thing
end

case item.class
when MyClass.class
  # do something here
when Array.class
  # do something different here
when String.class
  # do a third thing
end

出于某种原因,有时第一个有效而第二个无效,而其他时候,第二个有效而第一个无效。为什么?哪一种是“正确”的做法?

【问题讨论】:

  • 字符串是一个类。一个类的类是Class。
  • 注意MyClass === obj使用Module#===方法来检查obj是否是MyClass的实例。

标签: ruby duck-typing case-statement


【解决方案1】:

你必须使用:

case item
when MyClass
...

我遇到了同样的问题: How to catch Errno::ECONNRESET class in "case when"?

【讨论】:

  • 谢谢!很抱歉欺骗(或某种欺骗),但几次搜索都没有出现之前的问题。看来 case 语句使用 === 是一个很常见的问题,现在我发现这就是问题所在。这可能应该在教程等中更频繁地指出(但我敢打赌,许多教程作者也没有意识到这一点)。
  • 使用 ActiveRecord 时未提及的警告。类比较的 ActiveRecord === 方法使用 .is_a?,这意味着类的子类将在 case 语句中评估为 true。 github.com/rails/rails/blob/…
【解决方案2】:

是的,Nakilon 是正确的,您必须知道threequal === 运算符如何作用于when 子句中给出的对象。在红宝石中

case item
when MyClass
...
when Array
...
when String
...

真的

if MyClass === item
...
elsif Array === item
...
elsif String === item
...

理解 case 调用了一个 threequal 方法(例如MyClass.===(item)),并且可以定义该方法来做任何你想做的事情,然后你可以精确地使用 case 语句

【讨论】:

  • 如果我有arr = [],那么我注意到if Array === arr 将评估为true,但if arr === Array 将评估为false。有人可以帮忙解释一下吗?
  • === 只是一种方法,可以定义为类的设计者想要它做的任何事情。还要记住,a === b 真的意味着 a.=== b,所以如果你交换 a 和 b,你会得到不同的行为。不能保证 === 是可交换的。其实 Array === Array 是 false,但 Object === Object 是 true,所以 Array 是在重新定义 === 的语义。
【解决方案3】:

你可以使用:

case item.class.to_s
    when 'MyClass'

...当以下转折是不可能的:

case item
    when MyClass

原因是case 使用===the relationship the === operator describes is not commutative。例如,5Integer,但 Integer5?这就是你应该如何看待case/when

【讨论】:

  • "5 is an Integer, but is Integer a 5" 是一个非常人性化的解释,谢谢。
【解决方案4】:

在 Ruby 中,类名是一个常量,它引用描述特定类的 Class 类型的对象。这意味着在 Ruby 中说 MyClass 等同于在 Java 中说 MyClass.class

obj.classClass 类型的对象,描述obj 的类。如果obj.classMyClass,那么obj 是使用MyClass.new 创建的(粗略地说)。 MyClassClass 类型的对象,它描述了使用 MyClass.new 创建的任何对象。

MyClass.classMyClass 对象的类(它是Class 类型对象的,它描述了使用MyClass.new 创建的任何对象)。换句话说,MyClass.class == Class

【讨论】:

    【解决方案5】:

    这取决于您的 item 变量的性质。如果是对象的实例,例如

    t = 5
    

    然后

    t.class == Fixnum
    

    但如果它本身就是一个类,例如

    t = Array
    

    那么它将是一个Class 对象,所以

    t.class == Class
    

    编辑:请参考 Nakilon 所述的How to catch Errno::ECONNRESET class in "case when"?,因为我的回答可能是错误的。

    【讨论】:

    • 在 Ruby 中,一切都是“对象的实例”。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-07-16
    相关资源
    最近更新 更多