8

明智与否,我正在编写一个我只想接受 Scala 单例的方法,即通过“对象”实现的对象,而不是类或特征的构造实例。它应该接受任何类型的 Scala 单例,因此“MySingleton.type”不会这样做。

我遇到了一个非常奇怪的构造“scala.Singleton”,它没有在 api 文档中记录,但似乎可以解决问题:

scala> def check( obj : Singleton ) = obj
check: (obj: Singleton)Singleton

scala> check( Predef )
res0: Singleton = scala.Predef$@4d3e9963

scala> check ( new java.lang.Object() )
<console>:9: error: type mismatch;
 found   : java.lang.Object
 required: Singleton
              check ( new java.lang.Object() )

scala> check( Map )
res3: Singleton = scala.collection.immutable.Map$@6808aa2d

scala> check( Map.empty[Any,Any] )
<console>:9: error: type mismatch;
 found   : scala.collection.immutable.Map[Any,Any]
 required: Singleton
              check( Map.empty[Any,Any] )

然而,相当莫名其妙(对我来说),字符串文字被接受为单例,而显式构造的字符串不是:

scala> check( "foo" )
res7: Singleton = foo

scala> check( new String("foo") )
<console>:9: error: type mismatch;
 found   : java.lang.String
 required: Singleton
              check( new String("foo") )

为什么 String 字面量符合 Singleton?我是否误解了 Singleton 类型应该指定的内容?

4

3 回答 3

9

首先,什么是单例类型?如果你认为一个类型是一组值,那么单例类型就是一个只有一个元素的集合。

最常见的是,顶级对象可以居住在这样的集合中。

scala> object X
defined module X

scala> X: X.type
res41: X.type = X$@131d1cb

scala> res41: Singleton
res42: Singleton = X$@131d1cb

更一般地说,稳定值可以形成单例类型。

scala> object X { val y: String = "boo" }
defined module X

scala> X.y: X.y.type
res44: X.y.type = boo

scala> res44: Singleton
res45: Singleton = boo

如果y是 adef或 a var,它不再符合条件,因为随着时间的推移值可能会不同,因此编译器不能保证单例类型对一个且只有一个值进行分类。

scala> object X { def y: String = "boo" }
defined module X

scala> X.y: X.y.type
<console>:12: error: stable identifier required, but X.y found.
              X.y: X.y.type
                     ^

scala> object X { var y: String = "boo" }
defined module X

scala> X.y: X.y.type
<console>:12: error: stable identifier required, but X.y found.
              X.y: X.y.type
                     ^

还有一个限制:AnyVals 不能形成单例类型,因为语言规范明确将它们限制为AnyRef.

Paul Phillips 一直在策划一个允许您为文字表达单例类型的分支。

val xs: Stream[0.type](0)
val ys: Stream[0.type](0, 1) // does not compile
val x = xs.head // inferred type is 0.type, we statically know that this can only be 0!
于 2012-07-22T07:01:13.023 回答
6

据我所知,在这种情况下,每个不可变引用都有资格作为单例,而不仅仅是字符串。例如,您可以 ,invoke check(5)val foo = List(1,2,3); check(foo)var bar = List(1,2,3); check(bar)但是,将无法正常工作。

从这种行为来看,如果编译器可以确定它永远不会改变(或者在这种情况下是“最终的”),我会假设一个引用被认为是一个单例。

于 2012-07-21T18:45:32.527 回答
4

I think the easiest clue is comes from chapter 3 in the Scala Reference, section 3.2.1:

A singleton type is of the form p.type,where p is a path pointing to a value expected to conform (§6.1) to scala.AnyRef. The type denotes the set of values consisting of null and the value denoted by p.

A stable type is either a singleton type or a type which is declared to be a subtype of trait scala.Singleton.

The concept of stable types is important, and the trait makes it possible to declare things to be stable that would not otherwise be considered so.

于 2012-07-22T17:28:01.813 回答