2014-02-14 23 views
0

我不清楚爲什麼在下面的代碼片段中,foo被定義在「user」命名空間中,而不是我綁定的那個* ns *綁定關閉。有人能解釋我錯過了什麼嗎?在將* ns *綁定到別的東西后,定義一個變量

 
$ clj 
Clojure 1.4.0 

user=> (let [nspace (create-ns (gensym "sandbox"))] 
      (binding [*ns* nspace] 
        (print (ns-name *ns*)) 
        (def foo 6))) 
sandbox3#'user/foo 

user=> foo 
6 

user=> (in-ns 'sandbox3) 
# 

sandbox3=> foo 
CompilerException java.lang.RuntimeException: Unable to resolve symbol: foo in this context, compiling:(NO_SOURCE_PATH:0) 

sandbox3=> (def bar 7) 
#'sandbox3/bar 

sandbox3=> bar 
7 

sandbox3/user=> (in-ns 'user) 
# 

user=> foo 
6 

user=> bar 
CompilerException java.lang.RuntimeException: Unable to resolve symbol: bar in this context, compiling:(NO_SOURCE_PATH:0) 

回答

2

你需要使用eval:

(let [nspace (create-ns (gensym "sandbox"))] 
      (binding [*ns* nspace] 
        (print (ns-name *ns*)) 
        (eval '(def foo 6)))) 

eval注重*ns*,但大多數的Clojure的沒有。

編輯:是的,我只是建議,一個人使用eval:對

對於情況下,我一直在同運,他並不想真正的沙箱,因爲他信任的代碼進入他的系統,他只需要一種方法來評估不同名稱空間內的輸入代碼!

所以,如果你是這個問題的新手,你不是sethwm,請參閱Marczyk的答案。這個解決方案對於OP的用例非常具體,而不是通常很好的做任何事情的好方法。

+0

Augh,不!如果你絕對必須在另一個命名空間中定義變量(並且你可能不需要),使用'intern'。在這裏使用'eval'沒有任何理由。 – amalloy

5

def將創建Var的命名空間是在編譯時確定的。綁定不起作用(binding引入了運行時綁定)。

def應該只能用在頂層或內部像頂級let窗體。進一步偏離簡單頂級def,人們應該更加註重鍛鍊。例如binding肯定是類似於在許多方面頂級letdef表達式的值部分將與預期線程本地綁定到位評價:

user=> (let [nspace (create-ns (gensym "foo"))] 
     (binding [*ns* nspace] 
      (def foo *ns*))) 
#'user/foo 
user=> foo 
#<Namespace foo3> 

時尚中的無功是然而,在執行達到def表單時,首先創建的文件完全不受運行時狀態的影響。

要動態創建Vars,請使用intern - 這是一個具有完全可預測行爲的常規函數​​。

+0

謝謝邁克爾。 Re:實習生v def,我同意。但是我將在綁定中解釋其他人的代碼,並且無法控制他們是否使用def v實習生。我正在製作一個窮人的沙箱。 – sethwm

+0

有趣的是,他和我在這個問題之前實際上已經通過電子郵件相應。我保證,他的用例是合法的。 :P – Rayne

+0

@Rayne - 在你的良心上做到這一點。 :-P sethwm - 好的,在這種情況下,Rayne肯定是需要聯繫的人。出於好奇,爲什麼不使用/修改[clojail](https://github.com/Raynes/clojail)? –

相關問題