Clojure 如何使命名空间别名在初始编译后可用?

Clojure 如何使命名空间别名在初始编译后可用?,clojure,Clojure,我正在开发一个Clojure应用程序,它需要能够从shell命令行读取Clojure代码。应用程序有一个-main函数,该函数读取在命令行上传递的包含单个Clojure表单的字符串,并将该字符串传递给Clojure函数load string,该函数解析字符串并执行代码。它使用lein run和uberjar成功运行 我发现,如果在包含-main的文件顶部需要名称空间,则在命令行中传递的代码可以包含完全限定的名称空间名称。例如,如果源文件以 (ns popco.core.popco (:req

我正在开发一个Clojure应用程序,它需要能够从shell命令行读取Clojure代码。应用程序有一个
-main
函数,该函数读取在命令行上传递的包含单个Clojure表单的字符串,并将该字符串传递给Clojure函数
load string
,该函数解析字符串并执行代码。它使用
lein run
和uberjar成功运行

我发现,如果在包含
-main
的文件顶部需要
名称空间,则在命令行中传递的代码可以包含完全限定的名称空间名称。例如,如果源文件以

(ns popco.core.popco
  (:require [popco.core.reporters :as rpt]))
然后,我在命令行上传递的字符串可以通过
popco.core.reporters/ticker
引用我的函数
ticker
。但是,我不能使用别名
rpt
。如果我通过
rpt/ticker
引用
ticker
,我会得到一个异常:
java.lang.RuntimeException:没有这样的命名空间:rpt

我猜这是因为别名只在编译时可用,而且只有一个编译时可用。由于
load file
编译代码字符串的时间晚于源文件编译完成的时间,
rpt
不再可用作别名

允许我使用名称空间别名的解决方案是在
-main
中复制文件顶部的
require
s(我希望在repl中运行时使用)。然而,我可能需要包括几个名称空间,当然,复制代码是不可取的

还有别的解决办法吗?在repl中运行和从命令行运行代码时,是否有某种方法可以使别名定义一次


(编辑:以上关于编译时间的分析可能不太正确——或者我不理解Clojure编译。(事实上,我不理解Clojure编译!)上面两段中提到的解决方案使用
-main
中原始源代码中的
require
语句工作,而不仅仅是将字符串传递到
load file
。因此,在编译
-main
时,
require
将被编译,我想,这将是在与to相同的传递过程中我假设源文件的p。但是如果代码被输入到
-main
的定义中,那么
-main
中的代码不知何故在文件顶部的别名范围内,但如果它是通过
加载文件
引入的,则不会。但是当
时,通过
加载文件
引入的代码在别名范围内(需要时[popco.core.reporters:as rpt])
确实存在于
-main
的源代码中。为什么?

alias
函数需要通过
创建名称空间别名:as
键变异当前名称空间。也就是说,
alias
运行时的当前名称空间

这就是为什么
require
嵌入到您的
-main
定义中以您期望的方式创建别名:它正在改变您的运行时名称空间以包含给定的别名。值得强调的是,这不一定会改变
popco.core.popco
名称空间!事实上,这不太可能是runtim的工作名称空间e、 当调用
-main
时(它将在编译时,因此会像在
ns
宏中一样,改变所定义的ns)


这里的关键是要认识到运行时的
ns
并不总是定义了
-main
函数的
ns
,如果您想在运行时改变计算环境,您需要切换到正在改变的名称空间,或者改变您所在的名称空间。

感谢您的详细解释很有趣,也很有帮助。