[英]clojure dynamic binding, read-string and eval Unable to resolve symbol
(declare ^:dynamic symbol-table)
(defn answer []
(prn "blah")
(binding [symbol-table {:answer 42}]
(-> "[:h1 (:answer symbol-table)]" read-string eval)))
上面的代碼在repl中執行時按預期運行。 它返回
cpress.hsp> (answer)
"blah"
[:h1 42]
但是,當它在由http-kit生成的線程中執行時,出現無法解析的符號
Exception in thread "Thread-43"
java.lang.RuntimeException: Unable to resolve symbol: symbol-table in this context, compiling:(NO_SOURCE_PATH:0:0)
at clojure.lang.Compiler.analyze(Compiler.java:6792)
at clojure.lang.Compiler.analyze(Compiler.java:6729)
at clojure.lang.Compiler$InvokeExpr.parse(Compiler.java:3874)
at clojure.lang.Compiler.analyzeSeq(Compiler.java:7005)
at clojure.lang.Compiler.analyze(Compiler.java:6773)
在repl上對此進行模擬以生成一個線程來運行答案函數
(.. (Thread. answer) start)
為什么會發生這種情況以及如何解決?
一些實驗表明,由於命名空間的原因,它找不到符號。 例如,我不是從讀取字符串中獲取表達式,而是輸入文字
(defn answer2 []
(binding [symbol-table {:answer 42}]
(prn (eval `[:h1 (:answer symbol-table)])) ;;works
;;(eval '[:h1 (:answer symbol-table)]) ;; does not works
))
第一個eval使用有效的語法引用,但是當我使用常規引用時,它不起作用。 語法引用解析名稱空間,而常規引用則不能。 如果read-string返回帶有命名空間限定符號的表達式,那么它將解決我認為的問題,但read-string不會
當您運行eval時,在運行時將在當前名稱空間中解析表單中不合格的符號(而不是在定義函數的名稱空間中)。
為了解決這個問題,您可以創建一個eval版本,並將其命名空間綁定到所需的命名空間:
(defn local-eval [x]
(binding [*ns* (find-ns 'my-namespace)]
(eval x)))
(顯然,您需要更改my-namespace
以反映正確的名稱)。 然后使用它代替:
(defn answer []
(binding [symbol-table {:answer 42}]
(-> "[:h1 (:answer symbol-table)]" read-string local-eval)))
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.