【问题标题】:New behavior in Scala 2.10Scala 2.10 中的新行为
【发布时间】:2012-12-28 14:32:28
【问题描述】:

这里有两个 REPL 会话(受 this question 启发,虽然我的问题不同):

Welcome to Scala version 2.9.2 (Java HotSpot(TM) 64-Bit Server VM, Java 1.7.0).
Type in expressions to have them evaluated.
Type :help for more information.

scala> def ignore(it: String) = 42
ignore: (it: String)Int

scala> ignore(null.asInstanceOf[Nothing])
res0: Int = 42

还有:

Welcome to Scala version 2.10.0 (Java HotSpot(TM) 64-Bit Server VM, Java 1.7.0).
Type in expressions to have them evaluated.
Type :help for more information.

scala> def ignore(it: String) = 42
ignore: (it: String)Int

scala> ignore(null.asInstanceOf[Nothing])
java.lang.NullPointerException
        at .<init>(<console>:9)
        at .<clinit>(<console>)
        at .<init>(<console>:7)
        at .<clinit>(<console>)
        at $print(<console>)
        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
...

唯一的区别是第一个是 Scala 2.9.2,第二个是 2.10.0。

有人能指出导致这种新行为的 2.10 中的变化吗?

我知道强制转换为 Nothing 是一件很愚蠢的事情,而答案可能是“这都是未定义的行为,所以请停止这样做”,但它看起来可能会产生影响对于升级者,我不记得有任何讨论可以解释这一点。

【问题讨论】:

  • 由于 2.10 尚未稳定,因此将其列为错误可能是个好主意。如果不是,则应记录在案。如果是,应该在2.10final之前修复

标签: scala scala-2.10


【解决方案1】:

由于 Scala 对待 null 与选项上的 None 情况不同,即使 null 的值 Nothing 也是有问题的——Nothing 的实例应该正好为零,而不是一个实例可能或者可能不会损坏,具体取决于您的使用方式。

因此,我看不出旧的行为除了错误之外什么都不是。应该在发行说明中提到它已修复,但依靠 .asInstanceOf[Nothing] 来做 anything 保存抛出异常与类型理智完全相反,我认为不需要更多. (事实上​​,我什至认为不需要发行说明。)

【讨论】:

    【解决方案2】:

    这似乎只是控制台的问题,而不是语言的问题。如果你运行这个调用完全相同的方法的小应用程序,scala 2.10 没有问题。

    object Test extends App {
      override def main(args: Array[String]) {
        println(takesString(null.asInstanceOf[Nothing]))
      }
    
      def takesString(a: String) = 42
    }
    

    为了简化上面的示例,您只需键入

    null.asInstanceOf[Nothing]
    

    控制台会给你同样的错误。 我认为这与打印出类型有关。

    更新: 看起来我不小心碰到了 2.9.2。正如作者在评论中指出的那样,作为 2.10 RC5 中的脚本仍然失败。

    【讨论】:

    • 谢谢,但我实际上已经尝试过这个(或者类似的东西,无论如何),并且看到了与 REPL 中相同的行为。我也刚刚尝试编译和运行您的代码,但在 2.10.0(但不是 2.9.2)中确实出现了运行时错误。您使用的是哪个版本的 2.10.0?
    【解决方案3】:

    我知道您并不期待“这都是未定义的行为,所以 (...)”的答案,但是当您添加“可能对升级者产生影响的事情”时,我必须记住(即使很明显)根据自己的定义,人们不能依赖或期望任何事情具有未定义行为的事物的结果。

    在您提到的特定情况下,我认为这不是未定义的行为:它应该引发异常。 NothingNull 的子类,而不是相反 - 我的第一个期望,未经测试,是 null.asInstanceOf[Nothing] 行会抛出 ClassCastException,因为 null 不是 Nothing。但是,您可以看到 null 是一个特殊实例(就像在 Java 中一样)。尝试运行:

    scala> "aaa".asInstanceOf[Nothing]
    java.lang.ClassCastException: java.lang.String cannot be cast to scala.runtime.N
    othing$
            at .<init>(<console>:8)
            at .<clinit>(<console>)
    

    我猜这是因为在内部,obj.asInstanceOf[T] 调用 obj.getClass() 以便在运行时检查演员表。由于在null 上调用任何方法都会引发NullPointerException,因此该异常会在ClassCastException 之前引发。

    回到您的具体问题,似乎 Scala 2.9.2 以一种(非常)特殊的方式处理该特定情况。运行更多测试:

    scala> ignore(3.asInstanceOf[String])
    java.lang.ClassCastException: java.lang.Integer cannot be cast to java.lang.Stri
    ng
            at .<init>(<console>:9)
            at .<clinit>(<console>)
    scala> ignore({ println("test"); "aaa" })
    test
    res6: Int = 42
    

    您可以看到参数总是被评估,除了您的情况。 Scala 2.10 绝对具有最一致的行为。然而,这个问题不应该影响任何开发者升级到 Scala 2.10;我看不到任何obj.asInstanceOf[Nothing] 是正确代码的情况。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-10-27
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-04-04
      • 1970-01-01
      相关资源
      最近更新 更多