我对Common Lisp的破坏性DELETE函数有点困惑.它似乎按预期工作,除非项目是列表中的第一项:
CL-USER> (defvar *test* (list 1 2 3))
*TEST*
CL-USER> (delete 1 *test*)
(2 3)
CL-USER> *test*
(1 2 3)
CL-USER> (delete 2 *test*)
(1 3)
CL-USER> *test*
(1 3)
Run Code Online (Sandbox Code Playgroud)
请记住,DELETE应该在列表上工作,而不是在变量上工作.DELETE获取传递列表(指向第一个缺点的指针)而不是变量.
由于delete无法访问变量*test*,因此无法更改变量.'它'在这里意味着它的绑定.*test*将指向与以前相同的利弊细胞.唯一可以改变的是cons单元格的内容或第一个cons单元指向的其他cons单元格的内容.
有一件事是肯定的,无论如何DELETE,*test*总是指向相同的利弊细胞.
接下来是什么?如果你想*test*指向删除操作的结果,那么你明确地必须这样说:
(setq *test* (delete 1 *test*))
Run Code Online (Sandbox Code Playgroud)
"破坏性"并不意味着"就地运作".这意味着可以以某种任意且通常未定义的方式修改所操作的值的结构.在某些情况下,这可以实现具有效果,就好像它"就位"一样.然而,通常不能依赖于此.
如果使用破坏性运算符,则告诉编译器在操作完成后您对变量的先前值不感兴趣.您应该假设该值在之后无法识别,并且不再使用它.相反,您应该使用操作的返回值.
(let ((a (list 1 2 3)))
(let ((b (delete 2 a)))
(frob b))
a)
=> You were eaten by a grue.
Run Code Online (Sandbox Code Playgroud)
如果您不确定破坏性操作的安全性,请使用非破坏性对应物(remove在本例中).
(let ((a (list 1 2 3)))
(let ((b (remove 2 a)))
(frob b))
a)
=> (1 2 3)
Run Code Online (Sandbox Code Playgroud)
如果您确实想要修改变量的内容,请将它们设置为操作的返回值:
(let ((a (list 1 2 3)))
(setf a (delete 2 a))
a)
=> (1 3)
Run Code Online (Sandbox Code Playgroud)