Как установить Dynami c Var до компиляции - PullRequest
0 голосов
/ 12 марта 2020

Я хочу иметь переменную *flag* в данном пространстве имен, которая установлена ​​на true только при компиляции :aot.

Есть ли способ сделать это?

Ответы [ 3 ]

3 голосов
/ 13 марта 2020

Ваша проблема довольно сложна из-за определения собственной динамической природы c Clojure, поэтому нет грубого эквивалента C #ifdef или какого-либо другого механизма, который происходит во время компиляции, но вот обходной путь:

Я создал проект Leiningen с lein new app flagdemo. Этот трюк обнаруживает, когда выполняется AOT, как упоминалось выше @Biped Phill, используя Dynami c VAR *compile-files*, и сохраняет ресурс в пути к классам скомпилированного кода:

Код выглядит следующим образом:

(ns flagdemo.core
  (:gen-class))

(def flag-path "target/uberjar/classes/flag.edn")

(defn write-flag [val]
  (try (spit flag-path (str val)) (catch Exception _)))

(defn read-flag []
  (some-> (clojure.java.io/resource "flag.edn") slurp clojure.edn/read-string))

(write-flag false)

(when clojure.core/*compile-files*
  (write-flag true))

(defn -main
  [& args]
  (println "Flag is" (read-flag)))

Итак, когда файл загружает с помощью, скажем, lein run или когда вы загружаете его в REPL, он попытается записать файл EDN со значением false.

Когда вы компилируете пакет, используя lein uberjar, он загружает пространство имен и обнаруживает, что определено *compile-files*, таким образом он сохраняет файл EDN, упакованный с JAR, в качестве ресурса.

Функция read-flag просто пытается загрузить файл EDN из пути к классам.

Работает так:

$ lein clean
$ lein run
Flag is nil

$ lein uberjar
Compiling flagdemo.core
Created /tmp/flagdemo/target/uberjar/flagdemo-0.1.0-SNAPSHOT.jar
Created /tmp/flagdemo/target/uberjar/flagdemo-0.1.0-SNAPSHOT-standalone.jar

$ java -jar target/uberjar/flagdemo-0.1.0-SNAPSHOT-standalone.jar
Flag is true
2 голосов
/ 13 марта 2020

Благодарю @Biped Phill и @Denis Fuenzalida за объяснение мне.

Я думаю, что это также работает:

(def ^:dynamic *static* false)

(when (and *compile-files* boot/*static-flag*)
  (alter-var-root #'*static* true))

затем profiles.clj:

:injections [(require 'boot)
             (intern 'boot '*static-flag* true)]
0 голосов
/ 12 марта 2020

Сначала необходимо указать, что переменная со временем изменится:

(def ^:dynamic *the-answer* nil)
*the-answer*
;=> nil

Бит ^:dynamic позволит откатить эту переменную позже:

(binding [*the-answer* 42] *the-answer*)
;=> 42

ADDENDUM 1

Вот что произойдет, если вы не используете ^:dynamic:

(def *the-answer* nil)
(binding [*the-answer* 42] *the-answer*)
;=> [...] Can't dynamically bind non-dynamic var [...]

ADDENDUM 2

Переменные такого типа обычно называются "наушниками" . Соглашение об именах не применяется, но настоятельно рекомендуется.

Вот что происходит в REPL, когда вы используете это именование без объявления динамической c переменной:

(def *the-answer* nil)
; Warning: *the-answer* not declared dynamic and thus is not dynamically rebindable, but its name suggests otherwise. Please either indicate ^:dynamic *the-answer* or change the name. (/tmp/form-init7760459636905875407.clj:1)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...