繁体   English   中英

为什么不推荐使用Scala软件包对象中的类?

[英]Why are classes inside Scala package objects dispreferred?

从2.10开始, -Xlint抱怨软件包对象内部定义的类。 但为什么? 在包对象内定义类应该完全等同于在具有相同名称的单独包内定义类,只是更加方便。

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

例如,在我的情况下,我有一个util包,在它下面有许多子包( util.ioutil.textutil.timeutil.osutil.mathutil.distances等)将语义相关的功能,类甚至变量的异类集合进行分组。 我目前将所有各种函数,类等存储在util package object中的io.scalatext.scala或任何文件中的package object中。 这很好用,并且非常方便,因为可以混合使用函数和类,例如,我可以执行以下操作:

package object math {
  // Coordinates on a sphere

  case class SphereCoord(lat: Double, long: Double) { ... }

  // great-circle distance between two points
  def spheredist(a: SphereCoord, b: SphereCoord) = ...

  // Area of rectangle running along latitude/longitude lines
  def rectArea(topleft: SphereCoord, botright: SphereCoord) = ...

  // ...
  // ...

  // Exact-decimal functions
  class DecimalInexactError extends Exception

  // Format floating point value in decimal, error if can't do exactly
  formatDecimalExactly(val num: Double) = ...

  // ...
  // ...
}

没有这个,我将不得不根据乐趣与类而不是语义来不便地拆分代码。 我想,替代方法是将它们放置在普通对象中,这有点违背了将包装对象放在首位的目的。

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

精确地 语义(当前)是相同的,因此,如果您喜欢在包对象中定义类,则应该有充分的理由。 但是现实是,至少有一个很好的理由拒绝(继续阅读)。

除了更方便

这样更方便吗? 如果您这样做:

package object mypkg {
  class MyClass
}

您也可以执行以下操作:

package mypkg {
  class MyClass
}

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

现在,一个不让包对象过度使用的良好而具体的理由是,当包打开时包对象没有 打开 一种常见的情况是在多个项目之间分配代码,每个项目在同一包中定义类。 没问题 另一方面,包对象(与任何对象一样)是关闭的(如规范中所述:“每个包只能有一个包对象”)。 换句话说,您将只能在一个项目中定义一个包对象。 如果您尝试在两个不同的项目中为同一软件包定义一个软件包对象,则会发生不好的事情,因为您将有效地得到同一JVM类的两个不同版本(在我们的情况下,您将得到两个“ mypkg”。类”文件)。 根据情况的不同,您可能最终以编译器抱怨找不到它在包对象的第一个版本中定义的内容,或者得到“错误的符号引用”错误,甚至可能是运行时错误。 这是包对象的一般限制,因此您必须意识到这一点。 在包对象内部定义类的情况下,解决方案很简单:不要这样做(因为与仅将类定义为顶级相比,您不会获得任何实质性的收益)。 对于类型别名,vals和vars,我们没有这样的奢侈,因此在这种情况下,要权衡语法便利性(与在对象中定义它们相比)是否值得,然后注意不要定义重复的包对象。

对于这个语义上等效的操作为什么会产生皮棉警告,我还没有找到好的答案。 我认为这是一个皮棉错误。 我发现唯一不能放置在包对象内(相对于普通包内)的是实现main (或extends App )的对象。

请注意,即使无法在包范围内声明隐式类,-Xlint也会抱怨在包对象内部声明的隐式类。 (有关隐式类的规则,请参见http://docs.scala-lang.org/overviews/core/implicit-classes.html 。)

我想出了一个技巧,可以使包对象获得所有好处,而不必抱怨过时。 代替

package object foo {
  ...
}

你可以做

protected class FooPackage {
  ...
}

package object foo extends FooPackage { }

工作原理相同,但没有任何抱怨。 明确的迹象表明投诉本身是伪造的。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM