Разделение пространства имен Clojure на несколько файлов - PullRequest
89 голосов
/ 14 января 2011

Можно ли разделить пространство имен Clojure по нескольким исходным файлам при досрочной компиляции с :gen-class?Как (:main true) и (defn- ...) вступают в игру?

1 Ответ

134 голосов
/ 14 января 2011

Обзор

Конечно, вы можете, на самом деле clojure.core, само пространство имен разделено таким образом и дает хорошую модель, которой вы можете следовать, посмотрев в src/clj/clojure:

core.clj
core_deftype.clj
core_print.clj
core_proxy.clj
..etc..

Все эти файлы участвуют в создании единого пространства имен clojure.core.

Основной файл

Одним из них является основной файл, имя которого соответствует имени пространства имен, чтобы его можно было найти, когда кто-то упомянул его в :use или :require. В этом случае основным файлом является clojure/core.clj, и он начинается с формы ns. Здесь вы должны поместить all конфигурацию вашего пространства имен, независимо от того, какие другие файлы могут вам понадобиться. Обычно это также включает :gen-class, поэтому что-то вроде:

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

Затем в соответствующих местах в вашем основном файле (чаще всего в конце) используйте load для ввода вспомогательных файлов. В clojure.core это выглядит так:

(load "core_proxy")
(load "core_print")
(load "genclass")
(load "core_deftype")
(load "core/protocols")
(load "gvec")

Обратите внимание, что вам не нужен текущий каталог в качестве префикса, а также вам не нужен суффикс .clj.

Вспомогательные файлы

Каждый из вспомогательных файлов должен начинаться с объявления пространства имен, которому они помогают, но должен делать это с помощью функции in-ns. Таким образом, для приведенного выше примера пространства имен все вспомогательные файлы будут начинаться с:

(in-ns 'my.lib.of.excellence)

Это все, что нужно.

генераторной класс

Поскольку все эти файлы строят единое пространство имен, каждая определяемая вами функция может находиться в любом из основных или вспомогательных файлов. Это, конечно, означает, что вы можете определить свои функции gen-class в любом файле, который вам нужен:

(defn -main [& args]
  ...)

Обратите внимание, что нормальные правила порядка определения Clojure по-прежнему применяются ко всем функциям, поэтому вам нужно убедиться, что любой файл , определяющий функцию, загружен, прежде чем пытаться использовать эта функция.

Частные Вары

Вы также спросили о форме (defn- foo ...), которая определяет приватную функцию пространства имен. Функции, определенные так же, как и другие :private переменные, видны из пространства имен, в котором они определены, поэтому первичные и все вспомогательные файлы будут иметь доступ к закрытым переменным, определенным в любом из загруженных до сих пор файлов.

...