为什么 `lein uberjar` 评估用 `def` 定义的变量? [英] Why `lein uberjar` evaluates variables defined with `def`?

查看:16
本文介绍了为什么 `lein uberjar` 评估用 `def` 定义的变量?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我试图在创建 uberjar 时了解Lieningen"行为.以下是重现行为的最小示例:

I'm trying to understand "Lieningen" behaviour when creating an uberjar. Following is the minimal example which reproduces the behaviour:

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

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

(defn -main [& args]
  (println some-var))

当使用 lein run 执行时,它显然会失败并抛出异常.但是,我不明白为什么执行 lein uberjar 也会因变量定义中的异常而失败?为什么执行 lein uberjar 试图评估变量值?这是特定于 uberjar 任务还是我错过了关于 Clojure 或 Leiningen 的更重要的东西?

When this is executed with lein run it clearly fails with an Exception. However, I don't understand why executing lein uberjar also fails with an Exception from variable definition? Why executing lein uberjar attempts to evaluate the variable value? Is this speecific to uberjar task or am I missing something more substantial about Clojure or Leiningen?

推荐答案

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

In order to compile your namespace for the uberjar (if you have AOT turned on), the clojure compiler must load your namespace. This will always invoke all top-level side effects.

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

The best way to handle this is to never have side effects in top level code (whether inside or outside a def form), and have initialization functions to realize any start-up side effects needed.

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

A workaround can be to make a small namespace that uses introspection to load the rest of your code at runtime but not while compiling - using a function like this:

(defn -main
  []
  (require 'my.primary.ns)
  ((resolve 'my.primary.ns/start)))

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

if that namespace is compiled, the jvm can find -main and run it, despite none of your other code being compiled. The runtime require will cause the Clojure compiler to load the rest of your code at runtime only, and resolve is needed so that -main will compile cleanly - it returns the var referenced, which then invokes your function when called.

这篇关于为什么 `lein uberjar` 评估用 `def` 定义的变量?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆