2010-08-03 69 views
75

什么是包装物品,不是那么多概念,而是它们的用法?包装物品

我试图得到一个例子工作,我工作的唯一形式如下:

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_ { ... } 

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

看来,一个包对象必须在直接父包中声明,并且如果按照上面的方式写入,则需要大括号分隔包声明表单。

它们是否共同使用?如果是这样,怎么样?

+6

http://www.naildrivin5.com/scalatour/wiki_pages/PackageObjects – oluies 2010-08-04 10:41:44

+1

@Brent,这是一个很好的资源,不仅仅是包对象文章。我听说过作者,但没有意识到他会写这个Scala游览,谢谢。 – 2010-08-04 11:45:03

回答

113

通常你把你的包对象在一个单独的文件,它对应于呼包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客户端发出额外的导入来有效地使用您的库 - 例如,在斯卡拉摆动,你需要写

import swing._ 
import Swing._ 

让所有善良像onEDT和隐式转换从Tuple2Dimension

+12

注意事项:方法重载在程序包对象中不起作用。 – retronym 2010-08-04 05:20:11

+0

打败了我为什么选择将软件包对象定义在软件包层次结构的上一层。例如。这意味着如果你希望它属于你自己的根包,你需要用包对象污染虚拟的'org'或'com'顶层包。 'org.foo'。我发现允许定义直接在它应该是其一部分的包之下 - 将会是稍微适当的语言api界面。 – matanster 2015-10-02 16:22:22

7
+0

@亚瑟克鲁斯,谢谢,这似乎表明,他们需要一个单独的编译单元(这可能会得到大括号分隔包限制)。问题是我想得到一些可靠的用户建议,而不是我自己的猜测,关于如何使用它们。 – 2010-08-03 21:33:48

51

虽然Moritz的回答是现货,但还需要注意的一点是包对象是对象。除此之外,这意味着您可以使用混合继承来构建特性。莫里茨的例子可以写成

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 = // ... 

} 

这里版本是一个抽象的特质,它说,包对象必须有一个“版本”的方法,而JodaAliases和JavaAliases是包含手持式别名具体特征。所有这些特征都可以被许多不同的包对象重用。

+0

整个话题开放很多,似乎已经习惯了它的全部潜力,感谢另一个丰富的例子。 – 2010-08-04 19:05:00

+1

但它们不能用作vals,所以它们不是真正的对象 – 2013-08-08 16:23:04