Scala之旅-单例对象

Scala之旅-单例对象

单例对象(Singleton Objects)

通过使用关键字object代替class,使得单例对象中的方法(methods)和值(values)与类的各个实例没有关联。

package test

object Blah {
  def sum(l: List[Int]): Int = l.sum
}

这个方法sum全局可用,可以通过test.Blah.sum进行引用(referred)或者引入(imported)。

单例对象是定义一次性类(single-use class)的一种简写,它不能被实例化,在对象定义处是一个使用与类相同名字的val成员。和vals一样,单例对象可以作为特征(trait)或者类的成员,尽管这是非典型的用法。

单例对象可以扩展自类和特征。事实上,一个不带类型参数的case类(非泛型case类)会默认创建一个同名的单例对象,并且该单例对象实现了Function*特征。

同伴(Companions)

大部分单例对象都不是孤立的,而是和同名的类有关联。上面提到的case类的“同名单实例对象”就是这种例子。对于这种情况,单例对象叫做类的同伴对象,类叫做对象的同伴类。

Scaladoc对于在类和它的同伴之间的跳转有特殊支持:如果”C”或者”O”的圆圈下边缘是折叠起来的,就可以点击这个圆圈跳转到对应的同伴页面。

类和它的同伴对象必须定义在相同的源文件中。如下:

class IntPair(val x: Int, val y: Int)

object IntPair {
  import math.Ordering

  implicit def ipord: Ordering[IntPair] =
    Ordering.by(ip => (ip.x, ip.y))
}

typeclass实例作为隐式值(implicit values)是很常见的,例如上面的ipord,定义在同伴中,跟在typeclass模式之后。这是因为同伴的成员被包含在默认隐式搜索相关值的范围内。

Java程序员请注意

在Scala中static不是关键字。包括类在内的所有static成员都应该放入单例对象。它们可以用相同的语法引用,逐个引入或者作为一组引入,等等。

Java程序员经常把static成员定义成私有的,为它们的实例成员作为实现的帮助者(implementation aids)。这也可以用到同伴上来;一种通用的模式是在类中引入同伴对象的成员,像这样:

class X {
  import X._
  def blah = foo
}
object X {
  private def foo = 42
}

这个例子说明了另外一个特征:在私有环境中,类和它的同伴是友元(friends)关系。对象X可以访问类X的私有成员,反之亦然。为了使一个成员对其它成员真正意义上私有,需要使用private[this]

为了方便Java,直接定义在单例对象中的方法,包括vars和vals,也具有一个定义在同伴类中的static方法,叫做static forwarder。其它成员通过对象XX$.MODULE$ static域可以被访问。

如果将所有东西都转移到了同伴对象中,并且发现剩下的是一个你不想实例化的类,把类删掉即可。Static forwarders仍然会被创建。

参考资料

本文译自Tour Of Scala – Singleton Objects

上一篇:Scala之旅-模式匹配

下一篇:Scala之旅-正则表达式模式

发表评论

电子邮件地址不会被公开。 必填项已用*标注