下面的代码将z
作为局部变量,但它的行为就好像它是一个全局变量:
(defun foo (m)
(let ((z '(stuff nil)))
(push m (getf z 'stuff))
(print z)))
(foo 1)
(foo 2)
(foo 3)
我希望输出为
(STUFF (1))
(STUFF (2))
(STUFF (3))
T
但是当用SBCL运行时我看到了
(STUFF (1))
(STUFF (2 1))
(STUFF (3 2 1))
T
为什么会这样?这种行为是属性列表特有的吗?
答案 0 :(得分:6)
在foo
中,z
绑定到文字表达式'(stuff nil)
。该功能破坏性地改变了z
,从而破坏性地改变了文字的价值。 LISP在这种情况下的行为如何依赖于实现。某些实现将乖乖地改变文字值(如您的情况)。其他实现将文字放在只读内存位置,如果您尝试修改这些文字,则会失败。
要获得所需的行为,请使用COPY-LIST
复制可以安全修改的文字:
(defun foo (m)
(let ((z (copy-list '(stuff nil))))
(push m (getf z 'stuff))
(print z)))