我正在阅读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
而不是包含该行的文件。
为什么我会看到此行为,如何可靠地访问正在评估的文件的路径和文件名?
答案 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-file
,source-file
的返回值只是一个字符串,然后包含在foo
的编译版本中。然后,每次foo
执行时,该字符串都可用。
如果这种行为令人惊讶,那么为了使*file*
在运行时的每个函数中都有一个有用的值,可能需要考虑一下会发生什么。它的值必须为每个函数调用和返回而改变,这是很少使用的特性的大量运行时开销。