在多个文件上拆分Clojure命名空间

Ral*_*lph 89 namespaces compilation clojure

在进行提前编译时,是否可以在多个源文件上拆分Clojure命名空间:gen-class?怎么做(:main true)(defn- ...)发挥?

Cho*_*ser 135

概观

当然你可以,实际上clojure.core名称空间本身就是这样分开的,并提供了一个很好的模型,你可以通过查看src/clj/clojure:

core.clj
core_deftype.clj
core_print.clj
core_proxy.clj
..etc..
Run Code Online (Sandbox Code Playgroud)

所有这些文件都参与构建单个clojure.core命名空间.

主文件

其中一个是主文件,命名为匹配命名空间名称,以便在有人在:use或中提及它时找到它:require.在这种情况下,主文件是clojure/core.clj,它以ns表单开头.这是您应该放置所有命名空间配置的地方,无论您的其他文件可能需要它们.这通常包括:gen-class,所以像这样:

(ns my.lib.of.excellence
  (:use [clojure.java.io :as io :only [reader]])
  (:gen-class :main true))
Run Code Online (Sandbox Code Playgroud)

然后在主文件中的适当位置(最常见的是在最后)用于load引入辅助文件.在clojure.core它看起来像这样:

(load "core_proxy")
(load "core_print")
(load "genclass")
(load "core_deftype")
(load "core/protocols")
(load "gvec")
Run Code Online (Sandbox Code Playgroud)

请注意,您不需要当前目录作为前缀,也不需要.clj后缀.

帮助文件

每个帮助文件应首先声明它们正在帮助哪个命名空间,但应该使用该in-ns函数.因此,对于上面的示例命名空间,帮助程序文件都将以:

(in-ns 'my.lib.of.excellence)
Run Code Online (Sandbox Code Playgroud)

这就是全部.

创一流

因为所有这些文件都在构建单个命名空间,所以您定义的每个函数都可以位于任何主文件或辅助文件中.这当然意味着您可以gen-class在任何您喜欢的文件中定义您的函数:

(defn -main [& args]
  ...)
Run Code Online (Sandbox Code Playgroud)

请注意,Clojure的正常定义顺序规则仍然适用于所有函数,因此您需要确保在尝试使用该函数之前加载定义函数的任何文件.

私人瓦尔

您还询问了(defn- foo ...)定义命名空间私有函数的表单.:private从定义它们的命名空间中可以看到像这样定义的函数以及其他变量,因此主数据库和所有帮助程序文件都可以访问到目前为止加载的任何文件中定义的私有变量.

  • 截至今天,如果您确定需要多个文件来生成单个命名空间,那么这仍然是最佳实践.然而,现在它本身可能不像它那样普遍.另一种方法是在单个文件中定义ns的所有公共变量,并将所有帮助变量和函数移动到单独的"实现"命名空间.impl中的变量在技术上是公共的,但是ns文档字符串表明它们不是记录的API的一部分是常见的并且应该是足够的. (8认同)
  • 非常好,完整的答案!顺便说一下,我几乎完成了第一次通过_Clojure的喜悦_.好书! (2认同)