> 但是执行应该从 `-main` 方法开始,不是吗?
是的,主功能的执行是这样。运行所有 `ns` 和 `def` 形式也是执行。运行任何其他类型的高级代码也是执行。Clojure 的编译和执行是交织在一起的——这与其他语言的许多处理方式不同。这也是我们拥有令人惊叹的 REPL 体验的原因之一,这里的 "E" 部分与一开始就在某个 uberjar 中运行相同的代码没有差别。反之亦然——在正常情况下运行编译后的工件将不会与通过 REPL、逐行按正确顺序运行的原始代码有区别。
> 为什么变量会重新绑定?
它们并不是重新绑定。它们只是被绑定。uberjar 编译过程和使用该 uberjar 的过程是两个不同的过程,有相同的变量的两个不同的运行时版本。这与变量的值无关。
也许本节中的第二段会有所帮助:
https://clojure.org/reference/evaluation
> 假设我在计算某第 n 个斐波那契数,这需要几秒钟。为什么我需要在编译和运行时都付出这个代价?
首先,计算任何 N 的斐波那契数都不应该需要几秒钟。 :) 当然,但这不是重点。
“为什么”这个问题没有 straightforward 的答案,因为这并不是一个像“是的,必须支付两次成本,用户必须承受”这样的自觉决策。这只是 Clojure 的编译/评估方法的后果。
大多数情况下这类事情完全不重要,因为顶层代码都是纯粹的引用透明def,计算并不会花费任何值得注意的时间。
如果某些特定情况下并非如此,我提到了相应的解决方案——`延迟`和宏。