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

Scalaz `Tag.apply`: How does it work?

你好,我正在学习 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])

感谢您的帮助。

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

类型 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