¿Es posible dividir un espacio de nombres de Clojure en varios archivos de origen cuando se realiza una compilación anticipada :gen-class
? Cómo hacer (:main true)
y (defn- ...)
entrar en juego?
Respuestas:
Ciertamente puede, de hecho, el clojure.core
espacio de nombres en sí se divide de esta manera y proporciona un buen modelo que puede seguir mirando en src/clj/clojure
:
core.clj
core_deftype.clj
core_print.clj
core_proxy.clj
..etc..
Todos estos archivos participan para construir el clojure.core
espacio de nombres único .
Uno de ellos es el archivo principal, cuyo nombre coincide con el nombre del espacio de nombres para que se encuentre cuando alguien lo mencione en :use
o :require
. En este caso, el archivo principal es clojure/core.clj
y comienza con un ns
formulario. Aquí es donde debe poner toda su configuración de espacio de nombres, independientemente de cuál de sus otros archivos pueda necesitarlos. Esto normalmente también incluye :gen-class
, algo como:
(ns my.lib.of.excellence
(:use [clojure.java.io :as io :only [reader]])
(:gen-class :main true))
Luego, en los lugares apropiados en su archivo principal (más comúnmente todos al final) use load
para traer sus archivos de ayuda. En clojure.core
se ve así:
(load "core_proxy")
(load "core_print")
(load "genclass")
(load "core_deftype")
(load "core/protocols")
(load "gvec")
Tenga en cuenta que no necesita el directorio actual como prefijo, ni tampoco el .clj
sufijo.
Cada uno de los archivos auxiliares debe comenzar declarando a qué espacio de nombres están ayudando, pero debe hacerlo usando el in-ns
función. Entonces, para el espacio de nombres de ejemplo anterior, todos los archivos auxiliares comenzarían con:
(in-ns 'my.lib.of.excellence)
Eso es todo lo que se necesita.
Debido a que todos estos archivos están creando un único espacio de nombres, cada función que defina puede estar en cualquiera de los archivos principales o auxiliares. Esto, por supuesto, significa que puede definir sus gen-class
funciones en cualquier archivo que desee:
(defn -main [& args]
...)
Tenga en cuenta que las reglas de orden de definición normal de Clojure aún se aplican para todas las funciones, por lo que debe asegurarse de que cualquier archivo que defina una función esté cargado antes de intentar usar esa función.
También preguntó sobre el (defn- foo ...)
formulario que define una función privada de espacio de nombres. Las funciones definidas de esta manera, así como otras :private
vars, son visibles desde el espacio de nombres donde están definidas, por lo que el principal y todos los archivos auxiliares tendrán acceso a las vars privadas definidas en cualquiera de los archivos cargados hasta ahora.