* file *变量不起作用

时间:2012-10-02 14:51:11

标签: clojure

我正在阅读in the API docs *file*变量的值应为“正在评估的文件的路径,作为字符串”。但是,在某些情况下,此功能似乎已被破坏。

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

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

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

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

1 个答案:

答案 0 :(得分: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))

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

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

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

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