这是怎么回事?
你说:感觉这里没有什么特别的事情发生。外层foo
in bar
增加全局x
, and foo
被...围绕let
in bar
增加阴影x
。有什么大不了的?
The special这里发生的事情是这样的LET
can影子的价值*x*
。对于词法变量来说这是不可能的。
代码声明*x*
to be special通过DEFVAR
.
In FOO
现在的价值*x*
是动态查找的。FOO
将采取当前动态绑定 of *x*
或者,如果没有,则为符号的符号值*x*
. A new 动态绑定例如,可以引入LET
.
另一方面,词汇变量必须存在于词汇环境中的某个位置。LET
, LAMBDA
, DEFUN
其他人可以引入这样的词汇变量。请参阅此处的词法变量x
通过三种不同的方式介绍:
(let ((x 3))
(* (sin x) (cos x)))
(lambda (x)
(* (sin x) (cos x)))
(defun baz (x)
(* (sin x) (cos x)))
如果我们的代码是:
(defvar x 0)
(let ((x 3))
(* (sin x) (cos x)))
(lambda (x)
(* (sin x) (cos x)))
(defun baz (x)
(* (sin x) (cos x)))
Then X
were special在上述所有三种情况下,由于DEFVAR
声明,其中声明X
to be special- 全球所有级别。正因为如此,才有了这样的约定:special变量为*X*
。因此,只有周围有星星的变量才是special - by 习俗。这是一个有用的约定。
在你的代码中你有:
(defun bar ()
(foo)
(let ((*x* 20))
(foo))
(foo))
Since *x*
已宣布special通过DEFVAR
上面的代码中,LET
构造引入了一个新的动态绑定 for *x*
. FOO
然后被调用。由于里面FOO
the *x*
uses 动态绑定,它查找当前的并发现*x*
动态绑定到20
.
的值special在当前动态绑定中找到变量。
当地特别声明
当地也有special
声明:
(defun foo-s ()
(declare (special *x*))
(+ *x* 1))
如果变量已被声明special by a DEFVAR
or DEFPARAMETER
,那么本地的special
声明可以省略。
词法变量直接引用变量绑定:
(defun foo-l (x)
(+ x 1))
让我们在实践中看看:
(let ((f (let ((x 10))
(lambda ()
(setq x (+ x 1))))))
(print (funcall f)) ; form 1
(let ((x 20)) ; form 2
(print (funcall f))))
这里所有的变量都是词法的。在form 2 the LET
不会遮蔽X
在我们的函数中f
。不可以。该函数使用词法绑定变量,由LET ((X 10)
。用另一个词法绑定来包围调用X
in form 2对我们的功能没有影响。
咱们试试吧special变量:
(let ((f (let ((x 10))
(declare (special x))
(lambda ()
(setq x (+ x 1))))))
(print (funcall f)) ; form 1
(let ((x 20)) ; form 2
(declare (special x))
(print (funcall f))))
现在怎么办?那样有用吗?
它不是!
The 第一种形式调用该函数并尝试查找动态值X
但没有。我们得到一个错误form 1: X
未绑定,因为没有有效的动态绑定。
Form 2会起作用,因为LET
与special
声明引入了动态绑定X
.