我可以用一种简单的方法在 Scala 中获得一个未包装的单例类型吗?

Can I obtain an unwrapped singleton type in Scala with a simple method?

在 Scala 中,在围绕 Miles Sabin 的无形库的讨论中,我看到了这样的代码:

def sing[T <: String](t: T): Option[t.type] = Some(t)

像这样的地方:

val name = sing("name")

类型为 Option[Constant(name).type]。我想“为什么要用 Option 包装它”?但是如果我试试这个:

def sing2[T <: String](t: T): t.type = t
val name2 = sing2("name")

然后 name2 的类型为 String,而我本以为它是 Constant(name).type。我错过了什么?有没有不涉及包装单例类型的解决方法?

似乎 scalac 向上转换类型。我不知道,如果它是设计使然还是错误。如果强制输入:

def sing2[T <: String](t: T): t.type = t
val n = "name"
val name2: n.type = sing2(n)
// name2: n.type = name

您似乎无法构造 String(<string-literal>) 类型的值,只能使用限定名称:

scala> sing2("name")
res0: String = name

scala> val n = "name"
n: String = name

scala> sing2(n)
res1: n.type = name

但你不能说

val name2: n.type = sing("name")

因为

<console>:12: error: type mismatch;
 found   : String("name")
 required: n.type

也没有

name2: "name".type = sing2("name")
// or
name2: "name" = sing2("name")

但后者有工作:http://docs.scala-lang.org/sips/pending/42.type.html

这是 scalac 的一个已知怪癖。

单例类型是内部编译器,它们已经存在很长时间了,但从未打算向用户公开。因此,无法保证它们的 "API",事实上 scalac 会尽可能地使它们 "disappear"。

这几乎就是为什么 Miles 必须在需要时使用 Witness 类型来包装单例类型(例如可扩展记录键)的原因。

显然,将它们包装在一个容器中会导致编译器保留实际类型,这就是 Option 的情况。

正如 Oleg 在另一个答案中提到的,正在努力使单例类型正式成为语言的一部分:http://docs.scala-lang.org/sips/pending/42.type.html