为什么Scala包对象中的类不受欢迎?

时间:2013-06-24 07:21:19

标签: class scala object package deprecated

从2.10开始,-Xlint抱怨在包对象中定义的类。但为什么?在包对象中定义一个类应该完全等同于在具有相同名称的单独包中定义类,除了更方便。

在我看来,Scala中一个严重的设计缺陷是无法在文件的顶层放置除类实体之外的任何东西(例如变量声明,函数定义)。相反,你被迫将它们放入一个单独的“包对象”(通常在package.scala中),与它们所属的其余代码分开,并违反了与概念相关的基本编程规则。代码也应该是物理相关的。我没有看到任何理由为什么Scala在概念上不允许在较低级别允许的任何顶层级别,并且任何类非类似的东西都会自动放入包对象中,这样用户就不必担心它。

例如,在我的情况下,我有一个util包,在其下面我有许多子包(util.ioutil.textutil.time,{{1 }},util.osutil.math等)将函数,类和有时与语义相关的变量的异构集合分组。我目前将util.distances中的所有各种函数,类等存储在package object目录中名为io.scalatext.scala或其他任何文件的文件中。这很有效,而且非常方便,因为函数和类可以混合使用,例如我可以这样做:

util

如果没有这个,我将不得不根据乐趣与类而不是语义分解代码。我认为,替代方案是将它们放在一个普通的对象中 - 首先要破坏包装对象的目的。

3 个答案:

答案 0 :(得分:28)

  

但为什么呢?在包对象中定义一个类应该完全等同于在具有相同名称的单独包中定义类,

正。语义(目前)是相同的,所以如果你喜欢在包对象中定义一个类,那么应该有一个很好的理由。但实际情况是,至少有一个很好的理由不(继续阅读)。

  

除了更方便

那怎么更方便? 如果你这样做:

package object mypkg {
  class MyClass
}

您也可以执行以下操作:

package mypkg {
  class MyClass
}

你甚至可以在这个过程中保存几个字符:)

现在,一个没有过多使用包对象的一个​​好的具体原因是,当包打开时,包对象 。 一个常见的场景是将代码分派到多个项目中,每个项目在同一个包中定义类。这里没问题。 另一方面,一个包对象(就像任何对象一样)被关闭(正如规范所说的那样“每个包只能有一个包对象”)。换一种说法, 您只能在项目的一个中定义包对象。 如果你试图在两个不同的项目中为同一个包定义一个包对象,那么就会发生不好的事情,因为你最终会得到两个 同一个JVM类的不同版本(在我们的例子中,你最终会得到两个“mypkg.class”文件)。 根据具体情况,编译器可能会抱怨它无法找到您在包对象的第一个版本中定义的内容, 或者获得“错误的符号引用”错误,甚至可能是运行时错误。这是包对象的一般限制,因此您必须了解它。 在包对象内部定义类的情况下,解决方案很简单:不要这样做(假设与仅将类定义为顶级相比,您将不会获得任何实质性的东西)。 对于类型别名,vals和vars,我们没有这样的luxuary,所以在这种情况下,重要的是权衡句法的便利性(与在对象中定义它们相比)是否值得,然后注意不要定义重复的包对象。

答案 1 :(得分:1)

我没有找到一个很好的答案,为什么这个语义上等效的操作会产生一个lint警告。 Methinks这是一个棉绒虫。我发现一定不能放在包对象(vs普通包内)中的唯一一件事是实现main(或extends App)的对象。

请注意,-Xlint还会抱怨在包对象中声明的隐式类,即使它们不能在包范围内声明。 (有关隐式类的规则,请参阅http://docs.scala-lang.org/overviews/core/implicit-classes.html。)

答案 2 :(得分:-1)

我想出了一个技巧,它允许包对象的所有好处,而不会有关于弃用的抱怨。代替

package object foo {
  ...
}

你可以做到

protected class FooPackage {
  ...
}

package object foo extends FooPackage { }

同样但没有投诉。明确指出投诉本身是假的。