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)
,这允许我们将 Multiplication
与 Int
区别对待,但它会在运行时创建一个实际的 Multiplication
对象.
如果我们使用像 type Multiplication = Int
这样的类型别名,那么就没有运行时开销。但是现在 Multiplication
与 Int
无法区分,这不是我们想要的。
类型 Int @@ Multiplication
阻止我们将此类型的值直接用作 Int
,即使它在运行时实际上只是一个 Int
。
你好,我正在学习 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)
,这允许我们将 Multiplication
与 Int
区别对待,但它会在运行时创建一个实际的 Multiplication
对象.
如果我们使用像 type Multiplication = Int
这样的类型别名,那么就没有运行时开销。但是现在 Multiplication
与 Int
无法区分,这不是我们想要的。
类型 Int @@ Multiplication
阻止我们将此类型的值直接用作 Int
,即使它在运行时实际上只是一个 Int
。