考虑以下MWE:
(setq a-cat 'derpy)
(let ((cats '(fluffy derpy)))
(while cats
(print cats)
(setq cats (delq a-cat cats))
(print cats)
(print (pop cats))))
结果如下:
(fluffy derpy) ; original local binding of "cats".
(fluffy) ; "cats" after the removal of 'derpy ("a-cat").
fluffy ; the first and only element left in "cats" (with pop).
nil ; empty "cats" after pop. the loop is over.
如果我多次评估表达式,结果总是相同的。但是如果我把它包装在一个函数定义中,就会发生奇怪的事情:
(setq a-cat 'derpy)
(defun cats-test ()
(interactive)
(let ((cats '(fluffy derpy)))
(while cats
(print cats)
(setq cats (delq a-cat cats))
(print cats)
(print (pop cats)))))
(cats-test)
第一个结果(如预期的那样):
(fluffy derpy)
(fluffy)
fluffy
nil
第二个及后续结果:
(fluffy) ; "cats" local binding with only 1 element!??
(fluffy) ; "a-cat" wasn't found.
fluffy ; (pop cats).
nil ; end of loop.
如果我没有弄错的话,因为“猫”不是一个全局变量,所以在调用函数后它的值应保持不变。
如果我将表达式存储在匿名函数(使用(lambda ())
)并调用它(使用funcall
),结果与单独计算表达式相同,即没有奇怪的列表修改。 / p>
到底发生了什么?
编辑:
这可以防止在后续调用“cats-test”函数后修改列表:
(defun cats-test ()
(interactive)
(let ((cats (list 'fluffy 'derpy)))
(while cats
...
现在每次调用该函数时,都会通过list
函数(重新)定义“cats”局部变量的原始值。