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

Scalaz`Tag.apply`:它是如何工作的?,scala,scalaz,monoids,Scala,Scalaz,Monoids,您好,我正在学习高级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

您好,我正在学习高级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,乘法]
标记为[Int,乘法]

谢谢你的帮助。

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

类型
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类乘法(value:Int)
,这允许我们将
乘法
视为与
Int
不同,但它会在运行时创建一个实际的
乘法
对象

如果我们使用类型别名,如
type multiply=Int
,那么就没有运行时开销。但是现在,
乘法
整数
无法区分,这不是我们想要的


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

谢谢,这很有意义。它基本上是Scala 2.10之前的值类。这严格来说比值类更一般,因为
a@@T
中的类型
a
可以是任何类型,而不仅仅是值类中的
AnyVal
的子类型。@Apocalisp:No,值类可以用来包装不是AnyVal子类型的类型,如
class Foo(val底层:String)扩展了AnyVal
。但是在某些情况下,值类可能会导致运行时开销,请参阅。另一方面,标记类型方法将始终导致基本类型的运行时开销(
Int
成为JVM
Int
,但
Int@@Foo
成为
整数
),这是什么“高级Scala书?”我在谷歌上没有找到这样的书。这本书来自下划线: