当我尝试在方法中设置全局参数时,我遇到了一些奇怪的行为。
(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)
。
答案 0 :(得分:6)
当然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
破坏性地修改了cdr
列表文字的'(a)
,从而导致您观察到的行为。 (如果你没有优化,你可以随时使用append
来解决这个问题。)
您可能也对other answer关于此主题感兴趣。