明智与否,我正在编写一种方法,我只想接受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类型应该指定的内容?
答案 0 :(得分: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
是def
或var
,则它不再符合条件,因为随着时间的推移值可能不一样,因此编译器无法保证单例type对一个唯一的值进行分类。
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
^
另一个限制:AnyVal
s不能形成单例类型,因为语言规范明确地将它们限制为AnyRef
。
Paul Phillips一直在策划一个branch,它允许你为文字表达单身类型。
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!
答案 1 :(得分:6)
据我所知,每个不可变引用在此上下文中都有资格作为单例,而不仅仅是字符串。例如,您可以invoke check(5)
或val foo = List(1,2,3); check(foo)
。但是,var bar = List(1,2,3); check(bar)
将不起作用。
根据这种行为判断,如果编译器可以确定它永远不会改变(或者在这种情况下是'final'),我认为引用被认为是Singleton。
答案 2 :(得分:4)
我认为最简单的线索来自Scala Reference中的第3章,第3.2.1节:
单例类型的形式为p.type,其中p是指向a的路径 期望符合(§6.1)scala.AnyRef的值。类型表示 由null组成的值和由p。
表示的值稳定类型是单例类型或声明的类型 成为特征scala.Singleton的子类型。
稳定类型的概念很重要,而且这种特性使得可以宣布事物是稳定的,否则不会被认为是这样。