Scalaz 'Tag.apply': 它是如何工作的?



嗨,我正在学习高级 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),这允许我们将MultiplicationInt区别对待,但它会在运行时创建一个实际的Multiplication对象。

如果我们使用像type Multiplication = Int这样的类型别名,那么就没有运行时开销。但是现在MultiplicationInt没有区别,这不是我们想要的。

类型Int @@ Multiplication阻止我们直接将这种类型的值用作Int,即使它实际上只是运行时的一个Int

最新更新