52

我很难找到在 Clojure 中使用命名空间的好建议和常见做法。我意识到名称空间与 Java 包不同,所以我试图梳理出 Clojure 中的约定,这似乎很难确定。

我想我很清楚如何将函数拆分为 clj 文件,甚至大致了解我希望如何将这些文件组织到目录中。但除此之外,我很难找到适合我的开发环境的机制。一些相互关联的问题:

  1. 我对 Clojure 命名空间使用的唯一性约定是否与我通常用于 Java 包的唯一性约定相同?[即向后公司域.project.subsystem]
  2. 我应该将文件保存在与我的命名空间匹配的目录结构中吗?[阿拉爪哇]
  3. 如果我有多个命名空间,我是否需要将所有代码编译到一个 jar 中并将其添加到我的类路径中以使其可访问?
  4. 每个命名空间都应该编译成一个 jar 吗?或者我应该创建一个包含来自许多命名空间的 clj 代码的单个 jar?

谢谢...

4

2 回答 2

42
  1. 我想如果你认为它有帮助也没关系,但是许多 Clo​​jure 项目并没有这样做——参见。Compojure(使用顶级 compojure ns 和各种 compojure.* ns 用于特定功能)、Ring、Leiningen... Clojure 本身使用 clojure.*(和 clojure.contrib.* 用于 contrib 库),但这是一种特殊情况,我想。

  2. 是的!您绝对必须这样做,否则 Clojure 将无法找到您的命名空间。另请注意,您不得在命名空间名称中使用下划线或在文件名中使用连字符,并且无论您在命名空间名称中使用连字符的任何位置,都必须在文件名中使用下划线(以便 nsmy.cool-project在名为的文件cool_project.clj中定义名为my) 的目录。

  3. 你需要确保你所有的东西都在类路径中,但不管它是在一个 jar 中、多个 jar 中、文件系统上的 jar 和目录的混合......只要它遵守正确的命名约定(你的第 2 点)你应该没问题。

    但是,如果没有特别的理由,不要提前编译东西——这可能会阻止你的代码在 Clojure 的不同版本之间移植,除了稍微改进加载时间之外没有任何好处。

    有时您仍然需要使用 AOT 编译,特别是在某些 Java 互操作场景中——相关函数/宏的文档总是提到这一点。在 clojure.contrib 中有一些需要 AOT 的例子;我从来不需要它,所以我不能提供太多细节。

  4. 我会说您应该将 jars 用于代码的功能单元。例如,Compojure 和 Ring 被打包为包含许多名称空间的单个 jar,这些名称空间共同构成了整个包。此外,clojure.contrib 被打包为一个带有多个不相关库的单个 jar;但这又可能是一个特例。

    另一方面,包含所有项目代码及其依赖项的单个 jar 有时可能对部署很有用。如果您认为这种东西可能对您有用,请查看Leiningen 构建工具及其“uberjar”工具。

于 2010-02-08T17:06:58.500 回答
10
  1. 严格来说,没有必要,尽管许多 Java 项目也放弃了这种约定,特别是对于内部项目或私有 API。但是请避免使用单段命名空间,这会导致在默认包中生成类文件。
  2. 是的。

关于 3 和 4,打包和 AOT 编译与命名空间约定问题完全正交。

于 2010-02-08T17:14:06.733 回答