包对象

时间:2010-08-03 21:02:48

标签: scala scala-2.8

什么是包装对象,而不是概念,而是它们的用法?

我试图让一个例子正常工作,我开始工作的唯一形式如下:

package object investigations {
    val PackageObjectVal = "A package object val"
}

package investigations {

    object PackageObjectTest {
        def main(args: Array[String]) {
            println("Referencing a package object val: " + PackageObjectVal)
        }
    }
}

到目前为止我所做的观察是:

package object _root_ { ... }

是不允许的(这是合理的),

package object x.y { ... }

也是不允许的。

似乎必须在直接父包中声明包对象,如果如上所述,则需要以大括号分隔的包声明表单。

它们是否常用?如果是这样,怎么样?

4 个答案:

答案 0 :(得分:124)

通常,您会将包对象放在与其对应的包中名为package.scala的单独文件中。您也可以使用嵌套包语法,但这很不寻常。

包对象的主要用例是,当您使用包定义的API时,需要在包内的各个位置以及包外部进行定义。这是一个例子:

// file: foo/bar/package.scala

package foo

package object bar {

  // package wide constants:
  def BarVersionString = "1.0"

  // or type aliases
  type StringMap[+T] = Map[String,T]

  // can be used to emulate a package wide import
  // especially useful when wrapping a Java API
  type DateTime = org.joda.time.DateTime

  type JList[T] = java.util.List[T]

  // Define implicits needed to effectively use your API:
  implicit def a2b(a: A): B = // ...

}

现在,整个包foo.bar中可以使用该包对象中的定义。此外,当该包之外的人导入foo.bar._时,将导入定义。

通过这种方式,您可以阻止要求API客户端发布其他导入以有效地使用您的库 - 例如在scala-swing你需要写

import swing._
import Swing._

拥有onEDT之类的善意以及Tuple2Dimension的隐式转化。

答案 1 :(得分:56)

虽然莫里茨的答案很明显,但需要注意的另一件事是包装对象是对象。除此之外,这意味着您可以使用混合继承从特征构建它们。莫里茨的例子可以写成

package object bar extends Versioning 
                          with JodaAliases 
                          with JavaAliases {

  // package wide constants:
  override val version = "1.0"

  // or type aliases
  type StringMap[+T] = Map[String,T]

  // Define implicits needed to effectively use your API:
  implicit def a2b(a: A): B = // ...

}

此处Versioning是一个抽象特征,它表示包对象必须具有“version”方法,而JodaAliases和JavaAliases是包含方便类型别名的具体特征。所有这些特征都可以被许多不同的包对象重用。

答案 2 :(得分:7)

答案 3 :(得分:2)

  

包对象的主要用例是,当您使用包定义的API时,需要在包内以及包外的各个位置进行定义。

Scala 3 并非如此,原定于2020年中发布的based on Dotty的发布版本为in here

  

顶级定义

     

各种定义都可以写在顶层。
  不再需要打包对象,将逐步淘汰。

package p 

type Labelled[T] = (String, T) 
val a: Labelled[Int] = ("count", 1) 
def b = a._2 
def hello(name: String) = println(i"hello, $name)