【问题标题】:When and how many times can a clojure file be evaluated with leiningen?使用 leiningen 可以在何时以及多少次评估 clojure 文件?
【发布时间】:2014-11-21 04:18:22
【问题描述】:

我在向编写宏的代码添加警告时发现,文件主体在编译期间被执行了两次。是否有一个原因?这是 leiningen 特有的吗?我无法使用(compile ...) 重现此内容。

简化版:

(ns foo.core
    (:require foo.bar))

;; empty

(ns foo.bar)

(println "hello")

$ lein 编译:全部

编译 foo.core

hello

编译 foo.bar

hello

进一步的测试表明,命名空间在编译期间被重新加载到自身之上:

(ns foo.bar)

(declare wasd)
(println wasd)
(def wasd 2)

$ lein clean

$ lein 编译:全部

编译 foo.core

#<Unbound Unbound: #'foo.bar/wasd>

编译 foo.bar

2

在更复杂的情况下,我在编译期间发生了这种情况,然后每次从 lein 运行或启动 repl 时都会发生一次。我不确定为什么。这是 clojure 1.6 和 leiningen 2.5.0 的全部内容。

【问题讨论】:

    标签: clojure compilation leiningen


    【解决方案1】:

    Leiningen 对您的项目结构一无所知,就命名空间如何相互关联而言。因此,在编译项目时,lein 只需启动 JVM 并强制每次加载每个命名空间。这意味着,正如您所注意到的,命名空间将被重新加载,从而导致您注意到双重评估行为。

    相比之下,(clojure.core/compile) 只是加载绑定了clojure.core/*compile-files* 的目标资源。这将导致目标资源及其所需的所有资源被加载并编译到类文件中。但是,它不会像 Leiningen 的编译操作那样遍历你的整个项目结构来编译所有资源。

    【讨论】:

    • 我不明白。为什么“强制[ing]每个命名空间一次加载一个”意味着“将重新加载命名空间”?
    • 如果命名空间 A 需要 B,为了加载 A,必须先加载 B。因此,如果您先加载 A 然后加载 B,加载 A 将加载 B,然后您将导致 B 重新加载。
    • 这似乎是对的。检查compile task 的来源,它只是在每个文件上依次调用clojure.core/compile。我认为它背后有更多的“大脑”。
    • 谢谢你。我现在明白了。
    【解决方案2】:

    您在编译期间看到println 输出的原因是因为在命名空间评估期间调用了println。您的程序应该有一个-main fn 或其他调用println 的入口点。

    (defn -main [& _]
      (println "Won't see on compile.")
      (println "lein run -- is printing from -main"))
    

    我认为您的项目正在引发 Unbound Exception,因为您在为其分配值之前尝试使用 println 引用 wasd 变量。该变量已声明,但在 println fn 尝试获取该值之前未为其分配任何内容。

    【讨论】:

    • 该示例的重点是第二次变量已经绑定。它用于证明命名空间被加载了两次。最初的未绑定是预期的。
    猜你喜欢
    • 1970-01-01
    • 2019-02-18
    • 1970-01-01
    • 2020-09-26
    • 2019-02-18
    • 2012-11-06
    • 1970-01-01
    • 1970-01-01
    • 2020-11-11
    相关资源
    最近更新 更多