2009-10-06 36 views
65

我知道他們不同,因爲一個人設置*compile-path*而另一個沒有。不過,我需要幫助他們爲什麼不同。讓我們與Clojure的綁定

let用給定的綁定創建一個新的作用域,但binding ...?

回答

99

let爲某個值創建詞彙作用域不可變的別名。 binding爲某些Var創建動態範圍的綁定。

動態綁定意味着您的binding表單中的代碼以及該代碼調用的任何代碼(即使不在本地詞法作用域中)都會看到新的綁定。

考慮:

user> (def ^:dynamic x 0) 
#'user/x 

binding實際上創建了一個動態的Varlet結合僅陰影與本地別名VAR:

user> (binding [x 1] (var-get #'x)) 
1 
user> (let [x 1] (var-get #'x)) 
0 

binding可以使用合格的名稱(因爲它運行在Var s)和let不能:

user> (binding [user/x 1] (var-get #'x)) 
1 
user> (let [user/x 1] (var-get #'x)) 
; Evaluation aborted. 
;; Can't let qualified name: user/x 

let-引入的結合不可變。 binding -introduced綁定線程本地可變:

user> (binding [x 1] (set! x 2) x) 
2 
user> (let [x 1] (set! x 2) x) 
; Evaluation aborted. 
;; Invalid assignment target 

詞彙和動態綁定:

user> (defn foo [] (println x)) 
#'user/foo 
user> (binding [x 1] (foo)) 
1 
nil 
user> (let [x 1] (foo)) 
0 
nil 

Varslet見。爲讓VS結合

+4

這加上http://en.wikipedia.org/wiki/Scope_(programming)#Static_versus_dynamic_scoping真的提高我的理解。謝謝你,先生! – Carl 2009-10-06 22:21:42

+0

x必須與^:動態提示綁定,纔不會拋出錯誤,我說好。 – WeGi 2014-02-14 14:29:17

8

binding在每個線程的全球環境

至於你提到的let創建表示綁定新的作用域綁定一個值的名稱。

10

還有一個句法差異:

對於結合,前它們中的任何被綁定到VARS所有的初始值被評估。這與let不同,在那裏你可以在後面的定義中使用前一個「別名」的值。

user=>(let [x 1 y (+ x 1)] (println y)) 
2 
nil 

user=>(def y 0) 
user=>(binding [x 1 y (+ x 1)] (println y)) 
1 
nil 
+0

您需要^:dynamic來將x定義爲0(也是動態的),以使您的第二個示例可以工作。 – John 2014-02-21 07:38:20