这里有两个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
投射是一件愚蠢的事情,答案可能是“这是所有未定义的行为所以只是停止这样做”,但它看起来像是可能发生的事情对升级者有影响,我不记得碰到任何可以解释这一点的变化的讨论。
答案 0 :(得分:5)
由于Scala对null
选项的None
处理方式不同,即使null
值为Nothing
也存在问题,因此{的实例应该为零{1}},根据您的使用方式,不是一个可能会或可能不会中断的实例。
因此,我看不出旧的行为是什么,只不过是一个错误。应该在发行说明中说明它已被修复,但是依靠Nothing
来执行任何事情保存抛出异常与类型理智完全相反,我认为没有更多需要。 (事实上,我甚至不认为需要发布说明。)
答案 1 :(得分: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中的脚本失败。
答案 2 :(得分:2)
我知道你没有期待答案“这是所有未定义的行为,所以(...)”,但是当你添加“可能对升级者产生影响的东西”时,我必须记住(即使它很明显)根据自己的定义,人们不能依赖或期望任何具有未定义行为的事物的结果。
在您提到的特定情况下,我认为它不是未定义的行为:它应该抛出异常。 Nothing
是Null
的子类,而不是相反 - 我的第一个期望,即没有测试,就是null.asInstanceOf[Nothing]
行会抛出ClassCastException
,{{1 }}不是null
。但是,您可以看到Nothing
是一个特殊实例(就像在Java中一样)。尝试运行:
null
我的猜测是因为内部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
之前抛出该异常。
回到你的具体问题,似乎Scala 2.9.2以(非常)特殊的方式处理特定情况。再运行一些测试:
ClassCastException
除了您的情况,您可以看到始终正在评估参数。 Scala 2.10绝对具有最一致的行为。但是,此问题不应影响任何升级到Scala 2.10的开发人员;我无法看到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
是正确代码的任何情况。