【发布时间】:2020-04-08 19:39:05
【问题描述】:
我试图以无形的形式理解单例类型,并面临对单例类型编译时类型的误解。这是一个例子:
val x: Witness.`120`.T = 120.narrow
它工作正常,但这种结构看起来很不寻常。 Witness.120 是什么?在 IDE 中它指向一些宏函数 selectDynamic:
def selectDynamic(tpeSelector: String): Any = macro SingletonTypeMacros.witnessTypeImpl
它具有编译时类型Any 并通过构造Witness.120.T 和type 成员T 来判断。这看起来很神奇......任何人都可以解释一下当一个人写这样的东西时到底发生了什么:
val x: Witness.`120`.T = //...
【问题讨论】:
-
解释有点复杂,希望以后有人写一个更详细的答案。但是现在,让我给你一个简化。 Scala 的类型系统知道单例类型,因为 (几乎) 是第一个版本,例如
objects的类型。然而,对于文字 (例如120),直到2.13之前,我们没有办法在代码中表达和直接使用这些类型。无形见证为以前版本的 Scala 提供的是一种访问这些见证的方式。它作为一个 macro 工作,它生成Witness类的新实例,其 type parameterT是单例 -
@LuisMiguelMejíaSuárez 它作为一个宏来生成类 Witness 的新实例,其类型参数 T 是单例 你确定它会生成
Witness的子类型吗?我进行了一些实验,从编译错误中我看到它似乎是AnyRef{type T = Int(120); type ->>[V(in type ->>)] = V(in type ->>) with shapeless.labelled.KeyTag[Int(120),V(in type ->>)]; type Field[V(in type Field)] = V(in type Field) with shapeless.labelled.KeyTag[Int(120),V(in type Field)]}。非常疯狂的类型定义... -
是的,类型有点复杂,老实说,我不确定它是见证人的子类型还是只是匿名类。关键是,宏能够访问编译器的内部,在它们之间它可以找到
120(这里:type T = Int(120)) 的单例类型并让你使用它,它创建一个类的新实例,该实例具有 type member (type 参数是我之前评论中的拼写错误),其中包含此类类型,以便您可以访问它。选择动态是另一个复杂的部分,我不会深入了解它是如何工作的。
标签: scala generic-programming shapeless type-level-computation