【问题标题】:Some constructor with asInstanceOf一些带有 asInstanceOf 的构造函数
【发布时间】:2011-10-18 23:23:19
【问题描述】:

当我写我的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 参数是严格的。

为什么 Some 和 asInstanceOf 会出现这种奇怪的行为?

【问题讨论】:

  • 您使用的是哪个 scala 版本? 2.9.0.1 中的 REPL 在这两种情况下都会立即抛出异常。
  • 我复制了它,但在 2.8.1 上。很高兴知道它已修复。
  • Scala 2.8.1,我实际上在生产中使用了这个版本。很高兴知道是什么导致了这种行为以及它会在哪些情况下出现。

标签: scala option lazy-evaluation


【解决方案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 的评论,现在已修复。

【讨论】:

  • 接受这个,因为没有更多受过教育的解释。希望最终知道这个错误的确切原因。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2021-03-22
  • 2011-07-18
  • 2020-10-03
  • 2010-09-20
  • 1970-01-01
  • 1970-01-01
  • 2021-10-25
相关资源
最近更新 更多