我想在Clojure程序中创建Java Scanner
类的本地实例。为什么这样不起作用:
; gives me: count not supported on this type: Symbol
(let s (new Scanner "a b c"))
但它允许我像这样创建一个全局实例:
(def s (new Scanner "a b c"))
我原以为唯一的区别是作用域,但显然不是这样。 let
和 def
之间有什么区别?
问题在于你错误地使用了 let
。
let
的用法如下:
(let [identifier (expr)])
因此,你的示例应该像这样:
(let [s (Scanner. "a b c")]
(exprs))
你只能在 let 的作用域内(即括号之间)使用用 let 声明的词法绑定。let 只会创建一组词法绑定。我使用 def 来创建一个全局绑定,而使用 let 来绑定我想要它仅存在于 let 作用域中的内容,这样可以保持代码简洁。它们都有各自的用途。
注意:(Class.) 和 (new Class) 是相同的,只是语法糖不同。
LET不是"在当前范围内进行词法绑定",而是"创建一个新的词法作用域,并将下面的绑定放入其中"。
(let [s (foo whatever)] ;; 这里 s 被绑定了 ) ;; 但这里没有被绑定
(def s (foo whatever)) ;; s 在这里被绑定
简化版: def 用于全局常量,let 用于局部变量。
正确的语法:
(let [s (Scanner. "a b c")] ...)
let
看作是使用fn
创建一个新的词法作用域,然后立即应用它的语法糖。(let [a 3 b 7] (* a b)) ; 21
; vs.
((fn [a b] (* a b)) 3 7) ; 21
所以,您可以通过简单的宏和 fn
实现 let
:
(defmacro fnlet [bindings & body]
((fn [pairs]
`((fn [~@(map first pairs)] ~@body) ~@(map last pairs)))
(partition 2 bindings)))
(fnlet [a 3 b 7] (* a b)) ; 21
它们的语法不同,即使它们的含义是相关的。
let接受一个绑定(名称-值对)列表,后跟要在该绑定上下文中评估的表达式。
def只需要一个绑定,而不是列表,并将其添加到全局上下文中。