闭包: 闭包是可以包含自由(未绑定到特定对象)变量的代码块;这些变量不是在这个代码块内或者任何全局上下文中定义的,而是在定义代码块的环境中定义。“闭包” 一词来源于以下两者的结合:要执行的代码块(由于自由变量被包含在代码块中,这些自由变量以及它们引用的对象没有被释放)和为自由变量提供绑定的计算环境(作用域)。在 Scheme、Common Lisp、Smalltalk、Groovy、JavaScript、Ruby 和 Python 等语言中都能找到对闭包不同程度的支持。
lisp 里的闭包 并不是刻意造出来的,而是这种语言自带的。
例如:
CL-USER> (let ((x 0))
(defun y ()
(incf x 1)))
(let ((x 0))
(defun y ()
(incf x 1)))
Y
CL-USER> (y)
1
CL-USER> (y)
2
CL-USER> (y)
3
CL-USER>
闭包在这里是用了全局命名空间(global namespace)来保存其自由变量的值。
这带来的一个好处,就可以用闭包来保存代码里的私有信息,而不会暴露给其他代码
闭包在lisp 里的可视性是基于语法的(lexical scope)
lexical scope 的好处是这些绑定在编译后不需要为其实际分配任何内存 slot,
甚至一些显而易见的逻辑会被直接编译优化成简单的常量。
闭包在lisp里可以构造其他oo系统里的对象或者类的层次,对象变量等等,
在 let over lambda 结构中用 values 返回多个引用了相同 bindings 的 lambdas,可以实现 class 和 object.
下面的是一段抄来的代码:
? (let ((password nil)
(secret nil))
(defun set-password (new-passwd)
(if password
'|Can't - already set|
(setq password new-passwd)))
(defun change-password (old-passwd new-passwd)
(if (eq old-passwd password)
(setq password new-passwd)
'|Not changed|))
(defun set-secret (passwd new-secret)
(if (eq passwd password)
(setq secret new-secret)
'|Wrong password|))
(defun get-secret (passwd)
(if (eq passwd password)
secret
'|Sorry|)))
GET-SECRET
? (get-secret 'sesame)
|Sorry|
? (set-password 'valentine)
SECRET
? (set-secret 'sesame 'my-secret)
|Wrong password|
? (set-secret 'valentine 'my-secret)
MY-SECRET
? (get-secret 'fubar)
|Sorry|
? (get-secret 'valentine)
MY-SECRET
? (change-password 'fubar 'new-password)
|Not changed|
? (change-password 'valentine 'new-password)
NEW-PASSWORD
? (get-secret 'valentine)
|Sorry|
; The closed-over lexical variables aren't in the global environment
? password
Error: unbound variable
? secret
Error: unbound variable
; The global environment doesn't affect the closed-over variables
? (setq password 'cheat)
CHEAT
? (get-secret 'cheat)
|Sorry|
来自 “ ITPUB博客 ” ,链接:http://blog.itpub.net/133735/viewspace-719927/,如需转载,请注明出处,否则将追究法律责任。