当我尝试在方法中设置全局参数时,我遇到了一些奇怪的行为。
(defparameter *global-var-1* nil)
(defun method1 ()
(setf *global-var-1* '())
(format t "~a~%" *global-var-1*)
...
(loop
...
(setf *global-var-1* '(a))
(format t "~a~%" *global-var-1*)
(nconc *global-var-1* (list '(b c))))
在上面的代码中,当我调用 method1 时,第一个格式语句总是按预期打印 nil
。第二个格式语句在第一次调用 method1 时打印 (A)
,但在第二次调用时打印 (A (B C))
。第三次 (A (B C) (B C))
以此类推。 setf 似乎没有将 *global-var-1*
设置为 (A)
,而是将其设置为先前的已知值。我究竟做错了什么?顺便说一句,我将 *global-var-1
设置为 (A)
因为 nconc
不能处理空列表。我稍后在退出 method1 之前删除了 (A)
。
最佳答案
当然 nconc
适用于空列表,但您必须始终分配其返回值,如下所示:
CL-USER> (defparameter *x* nil)
*X*
CL-USER> (setq *x* (nconc *x* (list 'a)))
(A)
CL-USER> *x*
(A)
然后,您的问题通过不使用文字列表得到解决:
CL-USER> (defparameter *x* nil)
*X*
CL-USER> (defun foo ()
(setf *x* nil)
(dotimes (n 3)
(progn (setf *x* (list 'a))
(format t "~a~%" *x*)
(setf *x* (nconc *x* (list (list 'b 'c)))))))
FOO
CL-USER> (foo)
(A)
(A)
(A)
使用破坏性操作时应始终小心,并注意将它们与文字表达式一起使用的含义。在您的代码中,nconc
破坏性地修改了您的 '(a)
列表文字的 cdr
,这导致了您观察到的行为。 (如果您不进行优化,您总是可以使用 append
来解决这个问题。)
您可能也对我的 other answer 感兴趣关于这个话题。
关于lisp - 设置全局变量恢复到最后一个值,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/8044060/