> 但执行应该从 `-main` 方法开始,不是吗?
是的,是的,是指主功能执行。执行 `ns` 和 `def` 形式的代码也是执行。执行任何其他类型的顶层代码也是执行。Clojure的编译过程和执行过程是交织在一起的,这与其他许多语言的处理方式不同。这也是我们拥有伟大的REPL体验的原因之一,在那里“E”部分与在uberjar中有相同的代码几乎无法区分。反过来,在正常情况下运行编译后的工件和通过REPL逐行运行原始代码不会有太大的区别。
> 为什么变量会被重新绑定?
它们没有被重新绑定。只是被绑定了。uberjar编译过程和调用该uberjar的过程是两个不同的过程,拥有两个不同的相同变量的运行时版本。这与变量的值无关。
也许本节中的第二段会有所帮助:
https://clojure.org/reference/evaluation
> 比如我在计算某个第 n 个斐波那契数,这可能需要几秒钟。为什么我既要支付编译时的代价也要支付运行时的代价?
首先,计算任意N的斐波那契数不应该是几秒钟的事情。 :) 但当然,这不是重点。
“为什么”这部分没有直接答案,因为那不是像“是的,必须支付两次代价,用户必须忍受”这样的有意决定。这仅仅是Clojure的编译/评估方法的自然结果。
在这种情况下,这大部分时间都不是很重要,因为所有顶级代码都是纯引用透明的`def`,它们的计算时间不显著。
如果某个特定情况下不是这样,有解决方案,我已经提到了——`delay`和宏。