【问题标题】:Shapeless Witness and how it can give the actual singleton typeShapeless Witness 以及它如何提供实际的单例类型
【发布时间】: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.Ttype 成员T 来判断。这看起来很神奇......任何人都可以解释一下当一个人写这样的东西时到底发生了什么:

val x: Witness.`120`.T = //...

【问题讨论】:

  • 解释有点复杂,希望以后有人写一个更详细的答案。但是现在,让我给你一个简化。 Scala 的类型系统知道单例类型,因为 (几乎) 是第一个版本,例如 objects 的类型。然而,对于文字 (例如 120,直到 2.13 之前,我们没有办法在代码中表达和直接使用这些类型。无形见证为以前版本的 Scala 提供的是一种访问这些见证的方式。它作为一个 macro 工作,它生成 Witness 类的新实例,其 type parameter T 是单例
  • @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


【解决方案1】:

Witness 创建一个所谓的基于文字的单例类型字面量类型表示它是一种只能接受一个值的类型。

所以如果你创建一个这样的函数:

def f(x: Witness.`120`.T) = x

它只接受整数120,但不接受121

由于 Scala 2.13 literal types 已集成到语言中,因此您可以简单地写成:

def f(x: 120) = x

函数narrow 将值120 的类型从一般Int 缩小到文字120

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2023-03-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-05-07
    • 2020-09-17
    • 2017-03-15
    相关资源
    最近更新 更多