测试#1
我有一个全局声明的变量f
和一个名为f
的函数:
(defvar f 1)
(defun test (f)
f)
我调用该函数,它返回参数的值:
(test 2)
=> 2
测试#2
我再次有一个全局声明的变量
f
和一个名为f
的函数。但是,这次函数返回lambda
,它返回f
:(defvar f 1)
(defun test (f)
#'(lambda ()
f))
我调用该函数,它返回
lambda
函数。然后我调用lambda
函数,它返回全局f
的值:(funcall (test 2))
=> 1
我很惊讶。我以为
lambda
函数是一个闭包,将返回本地f
,而不是全局f
。如何修改test
函数和/或lambda
函数,以使lambda
函数返回本地f
,而不是全局f
?指向讨论此特定范围问题的在线资源的指针将不胜感激。
最佳答案
通过使用defvar
,您可以声明f
一个特殊的(又名动态绑定)变量。从此以后,代码中的f
不再按词法关闭,但实际上与立即更改为2的全局变量相同。
由于此功能,如果没有*earmuffs*
,则lispers对全局变量不满意。一旦有了*earmuffs*
,就可以更轻松地看到它:
(defvar *f* 1) ; special variable *f*
(defun test (*f*) ; momentarily rebind *f*
(format nil "*f* is ~a~%" *f*) ; use new value
#'(lambda () ; return lambda using *f*
*f*)) ; *f* goes back to being 1
(funcall (test 2)) ; ==> 1 (prints "*f* is 2\n")
因此,教训是:切勿在没有
*earmuffs*
的情况下创建全局变量,因为您将得到疯狂的运行时错误,几乎无法检测到。此命名约定不仅适用于时尚!关于文档,hyperspec实际上在
defparameter
and defvar
的示例中显示了动态变量的工作方式。看到他们调用(foo) => (P V)
,并且foo
在调用*p*
的过程中重新绑定*v*
和bar
,并且由于它们是动态绑定的,因此bar
使用更改后的值。关于common-lisp - 为什么lambda返回全局变量而不是局部变量?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/37667707/