比如 let 绑定和函数参数列表的变量在整个表达式内都是可见的,这有别于其 它语言词法作用域的变量。先看下面这个例子:
(defun binder (x) ; `x' is bound in `binder'. (foo 5)) ; `foo' is some other function. (defun user () ; `x' is used "free" in `user'. (list x)) (defun foo (ignore) (user)) (binder 10) ; => (10)
对于词法作用域的语言,在 user 函数里无论如何是不能访问 binder 函数中绑 定的 x。但是在 elisp 中可以。
(defun make-add (n) (function (lambda (m) (+ n m)))) ; Return a function. (fset 'add2 (make-add 2)) ; Define function `add2' ; with `(make-add 2)'. (add2 4) ; Try to add 2 to 4.
其它 Lisp 方言中有闭包,但是 emacs lisp 中没有。
说完这些概念,可能你还是一点雾水。我给一个判断变量是否有效的方法吧:
1. 看看包含这个变量的 form 中是否有 let 绑定这个局部变量。如果这个 form 不是在定义一个函数,则跳到第 3 步。 2. 如果是在定义函数,则不仅要看这个函数的参数中是否有这个变量,而且还 要看所有直接或间接调用这个函数的函数中是否有用 let 绑定或者参数列 表里有这个变量名。这就没有办法确定了,所以你永远无法判断一个函数中 出现的没有用 let 绑定,也不在参数列表中的变量是否是没有定义过的。 但是一般来说这不是一个好习惯。 3. 看这个变量是否是一个全局变量或者是 buffer-local 变量。
foo ; => "I'm local variable!" (boundp 'foo) ; => t (default-boundp 'foo) ; => t (makunbound 'foo) ; => foo foo ; This will signal an error (default-boundp 'foo) ; => t (kill-local-variable 'foo) ; => foo