10

这是两个 REPL 会话(受此问题启发,尽管我的问题不同):

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是一件愚蠢的事情,答案可能是“这都是未定义的行为,所以停止这样做”,但它看起来可能会对升级者产生影响,我不知道'不记得遇到任何可以解释这一点的变化的讨论。

4

3 回答 3

5

由于 Scala 对选项的处理null方式与Nonecase 不同,因此即使 的nullNothing也是有问题的—— 的实例应该正好为零Nothing,而不是一个实例可能会或可能不会中断,具体取决于您如何使用它。

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

于 2012-12-28T20:12:41.403 回答
3

这看起来只是控制台的问题,而不是语言的问题。如果你运行这个调用完全相同的方法的小应用程序,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 中的脚本仍然失败。

于 2012-12-28T14:54:06.960 回答
2

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

在您提到的特定情况下,我认为这不是未定义的行为:它应该引发异常。Nothing是 的子类Null,而不是相反-我的第一个期望,未经测试,是该行null.asInstanceOf[Nothing]会抛出 a ClassCastException,而null不是 a 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由于在throws a 上调​​用任何方法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]正确代码的情况。

于 2012-12-29T19:08:51.597 回答