上一节中,我们介绍了怎样构建一个是其它列表的尾端的列表:

    因为 的 cdrtail 是相等的,无论是修改 tail 还是 wholecdr ,我们修改的都是同一个 :

    1. > (setf (second tail ) 'e)
    2. > tail
    3. > whole

    一次修改两个对象并不总是错误的。有时候这可能正是你想要的。但如果无意的修改了共享结构,将会引入一些非常微妙的 bug。Lisp 程序员要培养对共享结构的意识,并且在这类错误发生时能够立刻反应过来。当一个列表神秘的改变了的时候,很有可能是因为改变了其它与之共享结构的对象。

    真正危险的不是共享结构,而是改变被共享的结构。为了安全起见,干脆避免对结构使用 setf (以及相关的运算,比如: poprplaca 等),这样就不会遇到问题了。如果某些时候不得不修改列表结构时,要搞清楚要修改的列表的来源,确保它不要和其它不需要改变的对象共享结构。如果它和其它不需要改变的对象共享了结构,或者不能预测它的来源,那么复制一个副本来进行改变。

    1.它对你传入的参数可能会有破坏性的操作

    2.你传入的参数可能被保存起来,如果你调用了一个函数,然后又修改了之前作为参数传入该函数的对象,那么你也就改变了函数已保存起来作为它用的对象[1]。

    在 Common Lisp 中,一个函数调用在遍历列表结构 (比如, mapcarremove-if 的参数)的过程中不允许修改被遍历的结构。关于评估这样的代码的重要性并没有明确的规定。