4

嗨,我正在学习 Advanced Scala 书,但我在理解 scalaz 源代码中的这段代码时遇到了一些麻烦:

object Tag {
  /** `subst` specialized to `Id`.
    *
    * @todo According to Miles, @specialized doesn't help here. Maybe manually specialize.
    */
  @inline def apply[@specialized A, T](a: A): A @@ T = a.asInstanceOf[A @@ T]

  // ...
}

它如何工作?a.asInstanceOf[A @@ T]应该因 ClassCastException 而失败,不是吗?

一个使用示例是:

Multiplication(2) |+| Multiplication(3) 

在这种情况下a是 Int 如何将其转换为@@[Int, Multiplication]( Tagged[Int, Multiplication])

谢谢您的帮助。

4

1 回答 1

12

这是因为erasure@@是一个纯粹的类型级构造,这意味着它没有运行时表示。

typeA @@ T是 type 的别名AnyRef{type Tag = T; type Self = A}。并且由于Int可以安全地转换为AnyRef(在引擎盖下,这是通过将 a 转换为 ajava.lang.Integer来完成的java.lang.Object),所以它工作得很好。

附加结构{type Tag = T; type Self = A}仅在编译时存在,因此在 JVM 进行强制转换时已完全擦除。

为什么要这样做?(我发音为“qua”)的目的@@是从旧类型创建新类型,而不会产生运行时开销。

例如,如果我们使用 ,case class Multiplication(value: Int)这允许我们将其视为Multiplication与 不同Int,但它会Multiplication在运行时创建一个实际对象。

如果我们使用类似的类型别名type Multiplication = Int,那么就没有运行时开销。但是 now与 a 没有Multiplication区别Int,这不是我们想要的。

该类型Int @@ Multiplication阻止我们将该类型的值直接用作 an Int,即使它实际上只是Int运行时的 a 。

于 2015-05-03T13:58:05.973 回答