嗨,我正在学习高级 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]
)
感谢您的帮助。
由于擦除,这有效。@@
是一个纯粹的类型级构造,这意味着它没有运行时表示形式。
类型A @@ T
是类型AnyRef{type Tag = T; type Self = A}
的别名。而且由于Int
可以安全地投射到AnyRef
(在引擎盖下,这是通过将java.lang.Integer
投射到java.lang.Object
来完成的),这工作得很好。
附加结构仅在编译时{type Tag = T; type Self = A}
存在,因此在 JVM 执行强制转换时已完全删除。
为什么要这样做?@@
(我发音为"qua")的目的是从旧类型创建新类型,而不会产生运行时开销。
例如,如果我们使用case class Multiplication(value: Int)
,这允许我们将Multiplication
与Int
区别对待,但它会在运行时创建一个实际的Multiplication
对象。
如果我们使用像type Multiplication = Int
这样的类型别名,那么就没有运行时开销。但是现在Multiplication
与Int
没有区别,这不是我们想要的。
类型Int @@ Multiplication
阻止我们直接将这种类型的值用作Int
,即使它实际上只是运行时的一个Int
。