Можно ли разделить пространство имен Clojure на несколько исходных файлов при предварительной компиляции с помощью :gen-class
? Как вообще (:main true)
и (defn- ...)
вступить в игру?
Ответы:
Конечно, вы можете, на самом деле 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
формы. Здесь вы должны поместить всю конфигурацию вашего пространства имен, независимо от того, какие из других ваших файлов могут нуждаться в них. Обычно :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
переменные видны изнутри пространства имен, в котором они определены, поэтому основной и все вспомогательные файлы будут иметь доступ к частным переменным, определенным в любом из файлов, загруженных на данный момент.