为什么`lein uberjar`评估用`def`定义的变量?

Tim*_*mur 7 clojure leiningen

我正在努力理解创建一个"Lieningen"时的行为uberjar.以下是重现行为的最小示例:

(ns my-stuff.core
  (:gen-class))

(def some-var (throw (Exception. "boom!")))

(defn -main [& args]
  (println some-var))
Run Code Online (Sandbox Code Playgroud)

执行此操作时lein run,显然会因异常而失败.但是,我不明白为什么执行lein uberjar也因变量定义的异常而失败?为什么要执行lein uberjar尝试来评估变量值?这是特定的uberjar任务还是我错过了关于Clojure或Leiningen更重要的内容?

noi*_*ith 12

为了编译uberjar的命名空间(如果你打开了AOT),clojure编译器必须加载你的命名空间.这将始终调用所有顶级副作用.

处理此问题的最佳方法是在顶级代码中(无论是在def表单内部还是外部)都没有副作用,并且具有初始化函数以实现所需的任何启动副作用.

解决方法可以是创建一个使用内省的小命名空间在运行时加载其余代码但不在编译时加载 - 使用如下函数:

(defn -main
  []
  (require 'my.primary.ns)
  ((resolve 'my.primary.ns/start)))
Run Code Online (Sandbox Code Playgroud)

如果编译了该命名空间,jvm可以找到-main并运行它,尽管你的其他代码都没有被编译.运行时require将使Clojure编译器仅在运行时加载其余代码,并且resolve需要以便-main干净地编译 - 它返回引用的var,然后在调用时调用您的函数.