为什么人们在 Scala 中的另一个对象中定义类、特征、对象?

发布于 2024-10-12 10:39:27 字数 633 浏览 6 评论 0原文

好的,我会解释为什么我问这个问题。这几天我开始阅读Lift 2.2源代码。 如果您之前碰巧读过 lift 源代码,那就太好了。

在Lift中,我发现定义内部类和内部特征被大量使用。

对象 Menu 有 2 个内部特征和 4 个内部类。对象 Loc 有 18 个内部类、5 个内部特征、7 个内部对象。

像这样写的代码有很多。我想知道作者为什么要这样写。

  • 是不是因为是作者的 个人品味或强大的使用 语言功能?
  • 这种有什么权衡吗 的用途?

Ok, I'll explain why I ask this question. I begin to read Lift 2.2 source code these days.
It's good if you happened to read lift source code before.

In Lift, I found that, define inner class and inner trait are very heavily used.

object Menu has 2 inner traits and 4 inner classes. object Loc has 18 inner classes, 5 inner traits, 7 inner objects.

There're tons of codes write like this. I wanna to know why the author write like this.

  • Is it because it's the author's
    personal taste or a powerful use of
    language feature?
  • Is there any trade-off for this kind
    of usage?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

仅一夜美梦 2024-10-19 10:39:27

在 2.8 之前,您必须在包和对象之间进行选择。包的问题是它们不能单独包含方法或值。所以你必须把所有这些都放在另一个对象中,这可能会很尴尬。观察:

object Encrypt {
  private val magicConstant = 0x12345678
  def encryptInt(i: Int) = i ^ magicConstant
  class EncryptIterator(ii: Iterator[Int]) extends Iterator[Int] {
    def hasNext = ii.hasNext
    def next = encryptInt(ii.next)
  }
}

现在您可以导入 Encrypt._ 并获得对 encryptInt 方法以及 EncryptIterator 类的访问权限。便利!

相比之下,

package encrypt {
  object Encrypt {
    private[encrypt] val magicConstant = 0x12345678
    def encryptInt(i: Int) = i ^ magicConstant
  }
  class EncryptIterator(ii: Iterator[Int]) extends Iterator[Int] {
    def hasNext = ii.hasNext
    def next = Encrypt.encryptInt(ii.next)
  }
}

这并不是一个巨大差异,但它使用户同时导入 encrypt._encrypt.Encrypt._ 或者必须保留一遍又一遍地编写Encrypt.encryptInt。为什么不像第一个模式那样只使用一个对象呢? (实际上没有性能损失,因为嵌套类实际上并不是底层的 Java 内部类;就 JVM 所知,它们只是常规类,但有一些奇特的名称告诉您它们是嵌套的。)

在 2.8 中,你可以鱼与熊掌兼得:将这个东西称为包对象,编译器会为你重写代码,所以它实际上看起来就像第二个例子(除了对象 Encrypt实际上在内部称为package),但在命名空间方面的行为类似于第一个示例——vals 和 defs 就在那里,不需要额外的导入。

因此,在 2.8 之前开始的项目通常使用对象来封装大量内容,就像它们是一个包一样。 2.8 之后,主要动机之一已被删除。 (但要明确的是,使用对象仍然没有坏处;更多的是它在概念上具有误导性,而不是对性能或其他方面产生负面影响。)

(PS 请不要尝试以这种方式实际加密任何内容除了作为例子或笑话!)

Before 2.8, you had to choose between packages and objects. The problem with packages is that they cannot contain methods or vals on their own. So you have to put all those inside another object, which can get awkward. Observe:

object Encrypt {
  private val magicConstant = 0x12345678
  def encryptInt(i: Int) = i ^ magicConstant
  class EncryptIterator(ii: Iterator[Int]) extends Iterator[Int] {
    def hasNext = ii.hasNext
    def next = encryptInt(ii.next)
  }
}

Now you can import Encrypt._ and gain access to the method encryptInt as well as the class EncryptIterator. Handy!

In contrast,

package encrypt {
  object Encrypt {
    private[encrypt] val magicConstant = 0x12345678
    def encryptInt(i: Int) = i ^ magicConstant
  }
  class EncryptIterator(ii: Iterator[Int]) extends Iterator[Int] {
    def hasNext = ii.hasNext
    def next = Encrypt.encryptInt(ii.next)
  }
}

It's not a huge difference, but it makes the user import both encrypt._ and encrypt.Encrypt._ or have to keep writing Encrypt.encryptInt over and over. Why not just use an object instead, as in the first pattern? (There's really no performance penalty, since nested classes aren't actually Java inner classes under the hood; they're just regular classes as far as the JVM knows, but with fancy names that tell you that they're nested.)

In 2.8, you can have your cake and eat it too: call the thing a package object, and the compiler will rewrite the code for you so it actually looks like the second example under the hood (except the object Encrypt is actually called package internally), but behaves like the first example in terms of namespace--the vals and defs are right there without needing an extra import.

Thus, projects that were started pre-2.8 often use objects to enclose lots of stuff as if they were a package. Post-2.8, one of the main motivations has been removed. (But just to be clear, using an object still doesn't hurt; it's more that it's conceptually misleading than that it has a negative impact on performance or whatnot.)

(P.S. Please, please don't try to actually encrypt anything that way except as an example or a joke!)

好多鱼好多余 2024-10-19 10:39:27

当您想要使用抽象类型变量时,有时需要将类、特征和对象放入对象中,请参见 http://programming-scala.labs.oreilly.com/ch12.html#_parameterized_types_vs_abstract_types

Putting classes, traits and objects in an object is sometimes required when you want to use abstract type variables, see e.g. http://programming-scala.labs.oreilly.com/ch12.html#_parameterized_types_vs_abstract_types

翻身的咸鱼 2024-10-19 10:39:27

两者都可以。除此之外,内部类/特征的实例可以访问其父类的变量。内部类必须使用父实例创建,该父实例是外部类型的实例。

在其他情况下,它可能只是对密切相关的事物进行分组的一种方式,如您的 object 示例中所示。请注意,LocParam 特征是密封的,这意味着所有子类必须位于同一编译单元/文件中。

It can be both. Among other things, an instance of an inner class/trait has access to the variables of its parent. Inner classes have to be created with a parent instance, which is an instance of the outer type.

In other cases, it's probably just a way of grouping closely related things, as in your object example. Note that the trait LocParam is sealed, which means that all subclasses have to be in the same compile unit/file.

攒眉千度 2024-10-19 10:39:27

sblundy 有一个不错的答案。需要补充的一件事是,只有 Scala 2.8 才有包对象,可以让您将类似的东西分组到包命名空间中,而无需创建完全独立的对象。因此,我将更新我的电梯模块提案,以使用包对象而不是简单对象。

sblundy has a decent answer. One thing to add is that only with Scala 2.8 do you have package objects which let you group similar things in a package namespace without making a completely separate object. For that reason I will be updating my Lift Modules proposal to use a package object instead of a simple object.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文