我试图使用delete
Common Lisp (SBCL) 中的函数从数组中删除一个元素,但注意到在调用以下命令后,该数组的所有索引仍然存在((length arr)
数组上的返回值不变)delete
:
(defparameter *x* (make-array 3 :initial-contents (list 13 26 39)))
*x* ; #(13 26 39)
(delete 26 *x* :test #'equal) ; #(13 39)
*x* ; #(13 39 39)
(length *x*) ; 3
Run Code Online (Sandbox Code Playgroud)
我假设*X*
调用后仍然可以访问 的第二个元素delete
,因为数组是连续的内存块,其中索引无法在不创建新数组的情况下“删除”。
我的困惑来自于setf
与 的结合使用delete
。这仅允许用户访问不受以下影响的元素delete
:
(defparameter *y* (make-array 3 :initial-contents (list 13 26 39)))
*y* ; #(13 26 39)
(setf *y* (delete 26 *y* :test #'equal)) ; #(13 39)
*y* ; #(13 39)
(length *y*) ; 2
Run Code Online (Sandbox Code Playgroud)
这是否意味着delete
在数组上调用时返回一个新数组?或者调用是否setf
创建一个新数组,以便(setf (delete ...))
有效地执行与 相同的操作(setf (remove ...))
?或者是*Y*
从上面一直指向同一个数组,只是第二个元素在幕后以某种方式被“忽略”?
如果您阅读 Common Lisp 标准(通常是 Common Lisp HyperSpec),那么它会说:
删除项目序列&key from-end test test-not start end count key => 结果序列
...
delete、delete-if 和delete-if-not 分别类似于remove、remove-if 和remove-if-not,但它们可能会修改顺序。
sequence
vector
是和的超类型list
。因此该函数delete
适用于向量和列表。
delete item sequence
表示所需的参数。
but they may modify sequence
then 意味着该函数可以修改作为参数提供的原始序列。可能修改 意味着实现的行为可能有所不同。
但无论如何你都需要使用返回的结果序列。这也相对容易记住,因为许多(但不是全部)函数通常返回结果,并且最好根据计算结果来思考,而不是作为具有副作用的过程。
请注意,Common Lisp 中的向量是可变对象。人们可以更改其内容,而无需分配新对象。另请注意:Common Lisp 提供了可能修改参数对象的破坏性函数。对于某些函数,该行为是预期的,而对于某些函数,它们是不应使用的副作用。delete
就是这样的后一个函数:参数序列可以更改并且该对象不应再使用。
示例1:
(defparameter *x* (make-array 3 :initial-contents (list 13 26 39)))
Run Code Online (Sandbox Code Playgroud)
上面使用提供的内容创建了一个长度为 3 的矢量对象。该变量*x*
指向该对象。
*x* ; #(13 26 39)
Run Code Online (Sandbox Code Playgroud)
上图:变量*x*
仍然指向最初创建的对象。
(delete 26 *x* :test #'equal) ; #(13 39)
Run Code Online (Sandbox Code Playgroud)
上图:#(13 39)
从调用中返回delete
。该值未被使用,只是返回。该变量*x*
仍然指向最初创建的向量对象。该对象可能已被更改。
*x* ; #(13 39 39)
Run Code Online (Sandbox Code Playgroud)
上图:变量*x*
仍然指向最初创建的对象。该对象已被调用破坏性地更改delete
。
(length *x*) ; 3
Run Code Online (Sandbox Code Playgroud)
上图:变量*x*
仍然指向最初创建的对象。它的长度仍然是3。
示例2:
(defparameter *y* (make-array 3 :initial-contents (list 13 26 39)))
Run Code Online (Sandbox Code Playgroud)
上面使用提供的内容创建了一个长度为 3 的矢量对象。该变量*y*
指向该对象。
*y* ; #(13 26 39)
Run Code Online (Sandbox Code Playgroud)
上图:变量*y*
仍然指向最初创建的对象。
(setf *y* (delete 26 *y* :test #'equal)) ; #(13 39)
Run Code Online (Sandbox Code Playgroud)
上图:变量*y*
被设置为调用返回的对象delete
:#(13 39)
。
*y* ; #(13 39)
Run Code Online (Sandbox Code Playgroud)
上图:变量*y*
指向delete
返回的新对象。
(length *y*) ; 2
Run Code Online (Sandbox Code Playgroud)
上图:变量*y*
仍然指向delete
返回的新对象。该物体的长度为 2。