当我写recent answer时,我也尝试以更“功能”的方式解决问题,但遇到了以下问题:
scala> "1".asInstanceOf[Int]
java.lang.ClassCastException: java.lang.String cannot be cast to java.lang.Integer
at scala.runtime.BoxesRunTime.unboxToInt(Unknown Source)
...
但
scala> Some("1".asInstanceOf[Int])
res29: Some[Int] = Some(1)
而且只有
scala> res29.get
java.lang.ClassCastException: java.lang.String cannot be cast to java.lang.Integer
at scala.runtime.BoxesRunTime.unboxToInt(Unknown Source)
...
看起来Some的论证是懒惰评估的,但我在the sources中找不到任何线索。 Some构造函数中的x参数是strict。
为什么有些asInstanceOf会有这么奇怪的行为?
答案 0 :(得分:2)
构造函数参数未被延迟评估。您收到错误的那一刻是REPL尝试显示结果的时刻,作为Int(unboxToInt
)。如果您进一步查看堆栈,可以找到scala_repl_result
。
我认为问题是asInstanceOf[Int]
在运行时根本没有检查。我不知道它是否符合规范(对于值类型)或bug。编译器被欺骗接受"1"
是Int
(或盒装Int),等待asInstanceOf隐含的运行时检查,但不会发生。
由于Option
/ Some
不是专门的,因此在运行时只有Some[Object]
。因此,对于JVM,调用构造函数new Some(Object o),它在代码验证和运行时被接受。 toString
(由新建的Some上的REPL调用)在通用代码中,其中T也被视为Object
(或AnyRef
),因此它可以工作,{{{ 1}}显示。另一方面,每次在编译器知道泛型参数的类型的上下文中访问值时,都会在代码中插入强制转换(在值类型的情况下为+ unboxing)。这是它实际失败的时候(这里REPL在显示之前进行拆箱)。
编辑这是在Scala 2.8.1中。根据@incrop上面的评论,现在已经修复了。