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添加任何附加的约束,因此typesT
和T {}
是等价的。 我们可以通过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为加宽typesString
而s2
被赋值为单例typesString("foo")
。
这是由SLS授权吗? 不,但它是一致的,这是有道理的。 Scala的许多types推断机制都是实现定义的,而不是专门定义的,这可能是最不令人惊讶和有问题的实例之一。