设置全局变量将恢复为上一个值

时间:2011-11-07 23:18:18

标签: lisp common-lisp

当我尝试在方法中设置全局参数时,我遇到了一些奇怪的行为。

(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)

1 个答案:

答案 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关于此主题感兴趣。