Scalaz`Tag.apply`:它是如何工作的?
您好,我正在学习高级Scala书籍,在理解scalaz源代码中的这段代码时遇到了一些问题: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
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
成为JVMInt
,但Int@@Foo
成为整数
),这是什么“高级Scala书?”我在谷歌上没有找到这样的书。这本书来自下划线: