Розбиття простору імен Clojure на кілька файлів


91

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

Відповіді:


137

Огляд

Звичайно, ви можете, насправді 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 ...)форму, яка визначає приватну функцію простору імен. Функції, визначені таким чином, а також інші :privatevars видно з простору імен, де вони визначені, тому основний та всі допоміжні файли матимуть доступ до приватних vars, визначених у будь-якому з завантажених до цього часу файлів.


3
Дуже приємна, повна відповідь! До речі, я майже закінчив свій перший прохід через "Радість Клоджура" . Чудова книга!
Ральф

Дякуємо, що поділилися цією відповіддю. Чи вважається це доброю практикою ще через 2 роки? (Я знаю, що все швидко змінюється.) Я бачу, що сам Клоджуре все ще використовує цю техніку.
Девід Дж.

9
На сьогоднішній день це все ще найкраща практика, якщо ви впевнені, що хочете, щоб кілька файлів створювали єдиний простір імен. Однак саме це зараз може бути рідше, ніж було раніше. Альтернативою може бути визначення всіх загальнодоступних варів ваших ns в одному файлі та переміщення всіх допоміжних варів та функцій в окремий простір імен "реалізації". Варіанти в impl технічно були б загальнодоступними, але ns документація, яка вказує, що вони не є частиною задокументованого API, є загальною і має бути достатньою.
Chouser

1
Чи знаємо ми, чи є у будь-якого поширеного інструментарію Clojure проблеми з розумінням просторів імен у декількох файлах? Лейн? Завантажити? Сидр? nREPL? Кібіт? Іствуд? Cloverage? І т.
Д.
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.