*file*变量不起作用

Jef*_*.D. 9 clojure

在API文档中读到*file*变量的值应为"正在评估的文件的路径,作为字符串".但是,在某些情况下,此功能似乎已被破坏.

当我使用文件执行时lein exec,事情按预期工作:

$ cat test.clj
(println *file*)
$ lein exec test.clj 
/path/to/test.clj
Run Code Online (Sandbox Code Playgroud)

然而,当我运行包含调用的测试时(println *file*),NO_SOURCE_PATH将打印而不是包含该行的文件.

为什么我会看到此行为,如何可靠地访问正在评估的文件的路径和文件名?

Cho*_*ser 13

*file*被设置为正在编译的文件的路径,因此在编译整个程序之后,查看*file*(假设不使用eval)的值不再有用.

在您的test.clj示例中,在println文件仍在编译时执行.如果将引用*file*移动到测试或函数中,则只有在值*file*不再有用后才会在运行时取消引用.

一种选择是编写一个存储*file*扩展时间值的宏,以便稍后使用.例如,文件example.clj可能具有:

(defmacro source-file []
  *file*)

(defn foo [x]
  (println "Foo was defined in" (source-file) "and called with" x))
Run Code Online (Sandbox Code Playgroud)

然后从REPL或任何地方,(foo 42)将打印:

Foo was defined in /home/chouser/example.clj and called with 42
Run Code Online (Sandbox Code Playgroud)

请注意,source-file定义哪个文件无关紧要,只有在展开的位置,即foo定义的文件.这是有效的,因为它是在运行时foo编译的source-file,并且其返回值source-file只是一个字符串,然后包含在编译版本中foo.然后,每次foo执行时都可以使用该字符串.

如果这种行为令人惊讶,那么为了*file*在运行时在每个函数中都有一个有用的值,可能需要考虑一下会发生什么.它的值必须为每个函数调用和返回而改变,这是很少使用的特性的大量运行时开销.