10

在 API 文档中读到该*file*变量应该具有“正在评估的文件的路径,作为字符串”的值。但是,在某些情况下,此功能似乎已损坏。

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

$ cat test.clj
(println *file*)
$ lein exec test.clj 
/path/to/test.clj

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

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

4

1 回答 1

14

*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))

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

Foo was defined in /home/chouser/example.clj and called with 42

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

如果这种行为令人惊讶,那么考虑必须发生什么以*file*在运行时在每个函数中具有有用的值可能会有所帮助。对于每个函数调用和返回,它的值都必须改变,对于一个很少使用的特性来说,这是一个巨大的运行时开销。

于 2012-10-02T15:09:20.267 回答