2012-10-02 195 views
9

我在閱讀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打印包含該行的文件,而不是。

爲什麼我會看到這種行爲,以及如何可靠地訪問被評估文件的路徑和文件名?

回答

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 was defined in /home/chouser/example.clj and called with 42 

注意,這並不重要文件source-file定義中,僅在它被擴展了,這是定義foo的文件。這是有效的,因爲foo編譯時運行的是source-file,而source-file的返回值只是一個字符串,然後包含在foo的編譯版本中。每當執行foo時,字符串當然可用。

如果這種行爲令人驚訝,可以考慮在運行時每個函數內部有一個有用的值,以便*file*有必要發生。它的值將不得不爲每個函數調用和返回而改變,對於一個很少使用的特性而言,它的運行時間開銷很大。

+0

很好的解釋;非常感謝! –