Scala中`T {}`是做什么的

浏览无形的代码,我在这里和这里看到这个看似无关的代码:

 trait Witness extends Serializable { type T val value: T {} } trait SingletonOps { import record._ type T def narrow: T {} = witness.value } 

我几乎将它视为一个错字,因为它什么都不做,但显然它做了一些事情。 看到这个提交: https : //github.com/milessabin/shapeless/commit/56a3de48094e691d56a937ccf461d808de391961

我不知道它是做什么的。 有人可以解释吗?

任何types都可以跟随一个封闭的types和抽象非types成员定义的序列。 这被称为“细化”(refinement),用于提高正在改进的基本types的附加精度。 在实践中,改进最常用于expression对正在改进的types的抽象types成员的约束。

这是一个鲜为人知的事实,这个序列被允许是空的,并且在无形的源代码中可以看到的forms, T {}是一个空的细化的typesT 任何空的细化是…空的…所以不会为精化types添加任何附加的约束,因此typesTT {}是等价的。 我们可以通过Scala编译器来validation对我们来说是这样的,

 scala> implicitly[Int =:= Int {}] res0: =:=[Int,Int] = <function1> 

那么为什么我会做这样一个毫无意义的事情呢? 这是因为精化的存在和types推理之间的相互作用。 如果您查看Scala语言规范的相关部分 ,您将会看到types推断algorithm至less在某些情况下试图避免推断单例types。 这只是一个例子,

 scala> class Foo ; val foo = new Foo defined class Foo foo: Foo = Foo@8bd1b6a scala> val f1 = foo f1: Foo = Foo@8bd1b6a scala> val f2: foo.type = foo f2: foo.type = Foo@8bd1b6a 

f2的定义可以看出,Scala编译器知道值foo具有更精确的typesfoo.type (即val foo的单例types),但除非明确要求,否则不会推断出更精确的types。 相反,它推断非单例(即加宽)types的Foo ,你可以看到在f1的情况下。

但是在无形的Witness的情况下,我明确地希望单值types被推断为value成员的使用( Witness的全部点使我们能够通过单例types在types和值级别之间传递),所以有什么办法Scala编译器可以被说服做到这一点?

事实certificate,一个空的提炼完全是这样的,

 scala> def narrow[T <: AnyRef](t: T): t.type = t narrow: [T <: AnyRef](t: T)t.type scala> val s1 = narrow("foo") // Widened s1: String = foo scala> def narrow[T <: AnyRef](t: T): t.type {} = t // Note empty refinement narrow: [T <: AnyRef](t: T)t.type scala> val s2 = narrow("foo") // Not widened s2: String("foo") = foo 

正如你可以在上面的REPL脚本中看到的,在第一种情况下, s1被input为加宽typesStrings2被赋值为单例typesString("foo")

这是由SLS授权吗? 不,但它是一致的,这是有道理的。 Scala的许多types推断机制都是实现定义的,而不是专门定义的,这可能是最不令人惊讶和有问题的实例之一。