具有防御性副本的SETQ或SETF

时间:2018-11-05 19:28:18

标签: common-lisp deep-copy shallow-copy defensive-copy

我想知道如何在Common Lisp中执行以下操作。假设我在内存中有一个在特定时间唯一的对象(实体)。我想做的是将某个变量设置为该对象的状态,作为特定时间的快照。然后原始实体可能会进化。但是,我想确保该变量过去仍指向该实体的状态。

看来,我需要的是深复制+ setter的内容。复杂的因素是,实体的性质有时是未知的。它可以是数组,也可以是哈希表。它可能同样是一个对象。

任何建议都值得赞赏。

1 个答案:

答案 0 :(得分:3)

您唯一需要的是不可变对象,并且仅更新绑定。 setq(和setf以符号作为第一个参数)可以完美地做到这一点。以下是一些示例:

(defparameter *test* '(1 2))
(defparameter *test2* *test*) ; a copy
(setf *test* (cdr *test*))    ; *test* is (2), but *test2* is still (1 2)
(defparameter *test3* *test*) ; a new copy
(setf *test* (cons 3 *test*)) ; *test* is (3 2), but *test2* is still (1 2) and *test3* is still (2)

pushpop为您完成此操作。这是相同的代码:

(defparameter *test* '(1 2))
(defparameter *test2* *test*) ; a copy
(pop *test*)                  ; *test* is (2), but *test2* is still (1 2)
(defparameter *test3* *test*) ; a new copy
(push 3 *test*)               ; (3 2), but *test2* is still (1 2) and *test3* is still (2)

在这里我不做的是(setf (car *test*) 3),因为这会使对象发生变化,并且所有引用都指向同一对象,因为它们指向我更改的对象。

因此,如果您具有某种更复杂的状态(例如哈希表),则需要将其变成一棵树,以便可以在每次更新时更改log(n)个节点,并且它将以相同的方式工作,则旧的引用仍具有相同的状态。