我正在尝试将一个列表传递给Lisp中的一个函数,并在该函数中更改该列表的内容,而不会影响原始列表。我读到过Lisp是按值传递的,这是真的,但还有一些我不太理解的事情。例如,此代码按预期工作:
(defun test ()
(setf original '(a b c))
(modify original)
(print original))
(defun modify (n)
(setf n '(x y z))
n)如果调用(test),即使(modify)返回(x,y,z),它也会打印(a,b,c)。
但是,如果您只尝试更改列表的一部分,则不会以这种方式工作。我假设这与列表有相同的内容,在所有地方的内存中都是相同的,或者类似的东西有关。下面是一个示例:
(defun test ()
(setf original '(a b c))
(modify original)
(print original))
(defun modify (n)
(setf (first n) 'x)
n)然后(test)打印(x B c)。那么,如何更改函数中列表参数的某些元素,就好像该列表是该函数的本地列表一样?
发布于 2009-09-27 20:18:17
SETF修改一个位置。n可以是一个地方。n指向的列表的第一个元素也可以是一个位置。
在这两种情况下,original保存的列表都作为其参数n传递给modify。这意味着函数test中的original和函数modify中的n现在都拥有相同的列表,这意味着original和n现在都指向它的第一个元素。
在第一种情况下,SETF修改了n之后,它不再指向该列表,而是指向一个新列表。original指向的列表不受影响。然后,modify返回新的列表,但是由于这个值没有被赋值给任何东西,所以它逐渐消失,很快就会被垃圾回收。
在第二种情况下,SETF不修改n,而是修改n指向的列表的第一个元素。这与original指向的列表相同,因此,之后,您还可以通过此变量查看修改后的列表。
要复制列表,请使用COPY-LIST。
发布于 2009-09-27 21:32:00
Lisp列表基于cons单元格。变量就像指向cons单元格(或其他Lisp对象)的指针。更改一个变量不会更改其他变量。更改cons单元格将在引用这些cons单元格的所有位置可见。
一本好书是Touretzky,Common Lisp: A Gentle Introduction to Symbolic Computation。
还有一款软件可以绘制列表和cons单元格的树。
如果您将列表传递给如下所示的函数:
(modify (list 1 2 3))那么你有三种不同的方式来使用这个列表:
cons细胞的破坏性修饰
(defun modify (list)
(setf (first list) 'foo)) ; This sets the CAR of the first cons cell to 'foo .structure共享
(defun modify (list)
(cons 'bar (rest list)))上面返回一个与传入的列表共享结构的列表:两个列表中的rest元素是相同的。
复制
(defun modify (list)
(cons 'baz (copy-list (rest list))))上面的函数BAZ类似于BAR,但没有共享列表单元格,因为列表是复制的。
不用说,通常应该避免破坏性修改,除非有真正的理由这样做(比如在值得的时候节省内存)。
备注:
从不破坏性地修改文字常量列表
不做:(let ((l '(a B C) (setf (first l) 'bar))
原因:该列表可能是写保护的,或者可能与其他列表共享(由编译器安排),等等。
另外:
引入变量
像这样
(let ((original (list 'a 'b 'c)))
(setf (first original) 'bar))或者像这样
(defun foo (original-list)
(setf (first original-list) 'bar))切勿设置未定义的变量。
发布于 2009-09-28 09:46:21
它与C语言中的这个示例几乎相同:
void modify1(char *p) {
p = "hi";
}
void modify2(char *p) {
p[0] = 'h';
}在这两种情况下都会传递一个指针,如果你改变了指针,你就改变了指针值的参数副本(它在堆栈上),如果你改变了内容,你就改变了指向的任何对象的值。
https://stackoverflow.com/questions/1484335
复制相似问题