我想Scanner
在 clojure 程序中创建 Java 类的本地实例。为什么这不起作用:
; 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 进行的词法绑定(左括号和右括号)。让我们创建一组词法绑定。我使用 def 来进行全局绑定,而让让我只在 let 的范围内绑定我想要的东西,因为它可以保持干净。他们都有自己的用途。
注意: (Class.) 与 (new Class) 相同,只是语法糖。
LET 不是“在当前范围内进行词法绑定”,而是“使用以下绑定创建新的词法范围”。
(让 [s (foo 随便)] ;; s 绑定在这里 ) ;; 但不是在这里
(def s (foo 随便)) ;; s 绑定在这里
简化:def用于全局常量,let用于局部变量。
正确的语法:
(let [s (Scanner. "a b c")] ...)
它们的语法是不同的,即使含义是相关的。
let 接受一个绑定列表(名称值对),后跟表达式以在这些绑定的上下文中求值。
def 只接受一个绑定,而不是一个列表,并将其添加到全局上下文中。
您可以将其let
视为创建新词法范围的语法糖,fn
然后立即应用它:
(let [a 3 b 7] (* a b)) ; 21
; vs.
((fn [a b] (* a b)) 3 7) ; 21
所以你可以let
用一个简单的宏来实现fn
:
(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