一些带有 asInstanceOf 的构造函数
当我写我的 最近的回答我也尝试以更“功能”的方式解决问题,但遇到了以下问题:
scala> "1".asInstanceOf[Int]
java.lang.ClassCastException: java.lang.String cannot be cast to java.lang.Integer
at scala.runtime.BoxesRunTime.unboxToInt(Unknown Source)
...
butscala> Some("1".asInstanceOf[Int])
res29: Some[Int] = Some(1)
and onlyscala> res29.get
java.lang.ClassCastException: java.lang.String cannot be cast to java.lang.Integer
at scala.runtime.BoxesRunTime.unboxToInt(Unknown Source)
...
看起来 Some 的参数是惰性评估的,但我在 来源。 Some 构造函数中的 x 参数是严格的。
为什么 Some 和 asInstanceOf 一起有如此奇怪的行为?
When I was writing my recent answer I also tried to solve the problem in more "functional" way, but stuck with the following problem:
scala> "1".asInstanceOf[Int]
java.lang.ClassCastException: java.lang.String cannot be cast to java.lang.Integer
at scala.runtime.BoxesRunTime.unboxToInt(Unknown Source)
...
but
scala> Some("1".asInstanceOf[Int])
res29: Some[Int] = Some(1)
and only
scala> res29.get
java.lang.ClassCastException: java.lang.String cannot be cast to java.lang.Integer
at scala.runtime.BoxesRunTime.unboxToInt(Unknown Source)
...
It looks like the Some's argument is lazy evaluated, but I can't find any clue in the sources. The x parameter in the Some constructor is strict.
Why does Some together with asInstanceOf has such a strange behavior?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
构造函数参数不会被延迟计算。收到错误的时刻是 REPL 尝试将结果显示为 Int (
unboxToInt
) 的时刻。如果您进一步查看堆栈,您会发现 scala_repl_result。我认为问题在于
asInstanceOf[Int]
在运行时根本不进行检查。我不知道它是根据规范(对于值类型)还是错误。编译器被欺骗接受"1"
是一个Int
(或装箱的 Int),等待 asInstanceOf 隐含的运行时检查,但这不会发生。由于
Option
/Some
没有专门化,因此在运行时只有Some[Object]
。所以对于JVM来说,有一个构造函数new Some(Object o)的调用,它在代码验证和运行时被接受。 toString(由新构建的 Some 上的 REPL 调用)位于通用代码内部,其中 T 也被视为Object
(或AnyRef
),因此它可以工作,并显示Some(1)
。另一方面,每次在编译器知道泛型参数类型的上下文中访问值时,都会在代码中插入强制转换(+ 在值类型的情况下拆箱)。这是它实际上失败的时候(这里 REPL 在显示之前进行拆箱)。编辑 这是 Scala 2.8.1 中的内容。根据上面@incrop 的评论,这个问题现在已经修复了。
The constructor argument is not lazily evaluated. The moment you get the error is the moment when the REPL try to display the result, as an Int (
unboxToInt
). If you look further in the stack, you findscala_repl_result
.I believe the problem is that
asInstanceOf[Int]
does no check at all at runtime. I don't know whether it is according to spec (for value types) or a bug. The compiler is tricked into accepting that"1"
is anInt
(or boxed Int), pending a runtime check implied by asInstanceOf, but which will not happen.As
Option
/Some
are not specialized, at runtime there is onlySome[Object]
. So for the JVM, there is a call to a constructor new Some(Object o), which is accepted at code verification and at runtime. ThetoString
(called by the REPL on the freshly built Some) is inside the generic code, where T is treated asObject
too (orAnyRef
), so it works, andSome(1)
is displayed. On the other hand, every time there is an access to the value in the context where the compiler knows the type of the generic parameter, a cast is inserted in the code (+ unboxing in case of a value type). This is when it actually fails (here REPL does unboxing before displaying).Edit This was in Scala 2.8.1. According to comment by @incrop above, this is now fixed.