【问题标题】:Packages in JVM languagesJVM 语言包
【发布时间】:2013-09-30 21:56:25
【问题描述】:

在 Java 中,通过将源文件放在像 com/acme/foo 这样的子目录中,将类放置在具有类似 package com.acme.foo 声明的包中

我正在开发一种 JVM 语言,旨在在风格上比 Java 更不要重复自己,因此我将使用这些机制中的一种或其他,但不会同时使用两者,并且我想知道使用哪个。

Scala 和 Clojure 等其他 JVM 语言如何处理它?它们需要两种机制还是只需要一种机制,如果需要,是哪一种?

【问题讨论】:

  • 两者都需要,就像 Java 一样。
  • 有趣。然后我想另一个问题是:假设他们不需要两者,您是否想要将您的源文件放在 com/acme/foo 中?或者,如果您可以将所有源文件直接放入项目的 src 目录中,而不需要子目录,您会更喜欢吗?
  • @arshajii: scalac 对源文件的路径(或名称)没有任何限制。
  • @TravisBrown 这是否意味着子目录放置是 Scala 程序员常用的约定,即使 scalac 不需要它?
  • @rwallace:是的。您偶尔会在 src/main/scala/ 下找到带有源文件的项目,但使用 Java 更为常见。

标签: java scala clojure jvm jvm-languages


【解决方案1】:

正如问题 Travis Brown 正确的 cmets 中所述,scalac 不会对源文件的路径或名称设置任何此类约束或限制,如果您愿意,您甚至可以在一个文件中指定多个包。

但是,由 scalac 生成的字节码会将字节码类文件放在适当的类加载器所需的必要目录结构中。

这里有一些展示灵活性的例子(我不一定提倡这些风格,只是展示灵活性)。

// in packages1.scala file in local directory
package my {
  package states {
    sealed trait State
    case class CheckingOut(shoppingCartId: Long) extends State
    case class ConfirmedOrder(orderId: Long) extends State
    case class ItemShipped(orderId: Long, itemId: Long, quantity: Int) extends State
  }
}

还有这个……

// in packages2.scala file
package com.foo.bar

sealed trait Scale
case object WebScale extends Scale
case object LolScale extends Scale
case object RoflScale extends Scale
case object WatScale extends Scale

而且这种风格也是可以的:

// in packages3.scala file
package foo {
  package awesomeness {
    class Main extends App {
      println("Bananas are awesome")
    }
  }
}

package foo {
  package lameness {
    class Main extends App {
      println("Congress is pretty lame, honestly")
    }
  }
}

还有这个……

package foo
package bar

// now we are in package foo.bar for remainder of file unless another package statement is made

这是生成的源代码和编译后的字节码树:

$ tree
.
├── com
│   └── foo
│       └── bar
│           ├── LolScale$.class
│           ├── LolScale.class
│           ├── RoflScale$.class
│           ├── RoflScale.class
│           ├── Scale.class
│           ├── WatScale$.class
│           ├── WatScale.class
│           ├── WebScale$.class
│           └── WebScale.class
├── foo
│   ├── awesomeness
│   │   ├── Main$delayedInit$body.class
│   │   └── Main.class
│   └── lameness
│       ├── Main$delayedInit$body.class
│       └── Main.class
├── my
│   └── states
│       ├── CheckingOut$.class
│       ├── CheckingOut.class
│       └── State.class
├── packages1.scala
├── packages2.scala
└── packages3.scala

8 directories, 19 files

我不确定 Clojure 是否支持这种灵活性,但 Clojure 约定是使用 Java 构造源代码的约定及其常用的构建工具lein(参见leiningen tutorial here)。

然而,需要注意的一点是,在 Scala 和 Clojure 中,似乎都偏离了 Java 世界中经常使用的 $DOMAIN.$APPLICATION 格式(例如,com.oracle.jdbc...org.hibernate.session... 等) .在 Scala 中,您会看到包名的 $DOMAIN 部分被完全取出(例如 scalaz...akka.{actor,io, ...} 等)。

另外值得注意的是您可以从 Scala 中的包中导入的方式:

  • 导入foo.bar 包中的所有公共“事物”:import foo.bar._
  • 只导入一个类/特征/等(就像 Java):import foo.bar.Baz
  • 从包中导入一个类/特征/等并在当前范围内重命名:import foo.bar.{Baz => FooBarBaz}
  • 从包中导入一部分东西:import foo.bar.{Baz, Boo, Bla}

另外值得注意的是 Scala 中的包私有作用域:

package foo.bar

class Baz{
  private[bar] def boo[A](a: A)
  private[foo] def bla[A](a: A)
}

boo 以上是 foo.bar 包(和子包)私有的,blafoo 及其所有子包的私有。

有关更多详细信息,请阅读 Scala 语言规范和相关链接:

【讨论】:

    【解决方案2】:

    Clojure 有点像 Java,但没有真正的类,所以有点不同。

    如果有命名空间 project.foo,那么 Clojure 编译器将期望在名为 foo.clj 的文件的源根目录下的项目目录中找到它。

    例如假设 src 是保存源文件的目录。然后 project.foo 命名空间将位于 src/project/foo.clj 中,并在顶部带有类似 (ns project.foo) 的声明。

    我认为这真的很难摆脱,因为在运行时,当 Clojure 去加载文件时(大多数 Clojure 被捆绑为源),Clojure 运行时会将文件作为资源加载,这需要它在目录层次结构中的正确位置(无论是基于 jar 还是基于文件)。

    就我个人而言,我也不介意包名 == 目录位置约定。它使工具可以在编译或运行时轻松查找文件,如果我只是使用 emacs,我也可以轻松找到它们。与目录中的一堆文件相比,它也感觉更有条理,尽管这可能更多的是我在使用它之后习惯的问题。

    【讨论】:

      【解决方案3】:

      我对 Clojure 没有任何经验,但我确实对 Scala 有一些经验,而且 scala 也使用子目录作为它们的包,但其中一个漂亮的特性是能够重命名类,类似于 C++ typedef 关键字功能.一个有趣的想法是,如果您创建了一个类似于 C++ 的链接器并允许 typedef 功能但仍将其保留在 JVM 中。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-04-09
        • 1970-01-01
        • 2012-07-14
        • 1970-01-01
        • 2010-10-17
        • 1970-01-01
        相关资源
        最近更新 更多