سؤال

How do I copy a structure in Common Lisp? I created a structure like:

(defstruct state board player previous-move depth)

Board is a 2 dimension array. I tried doing:

(setf new-state state)

When I change something in new-state, the changes in the 2 dimension array also occur in state. How can I create a copy of a structure like state and change it independently?

هل كانت مفيدة؟

المحلول

Common Lisp gives you two ways:

  • with DEFSTRUCT state there is a function copy-state defined.

  • the function COPY-STRUCTURE copies a structure

Note that these are shallow copies. Only the slot references get copied. There won't be a copy of the referenced data.

To copy the array, you would need to write a routine (possibly there are library routines).

نصائح أخرى

It’s possible the following generic method may work (ie, produce a deep copy of a structure object), although it is not guaranteed to work in every Common Lisp implementation, and certainly is not portable. It does not conform to the Common Lisp Hyperspec, since it tries to apply class functions to structures. But it might be worth a try for personal use.

(defmethod deep-copy ((struct structure-object))
  "Copy a structure recursively."
  (let ((new-struct (copy-structure struct))
        (slots (class-direct-slots (class-of struct))))
    (dolist (slot slots)
      (let ((slot-name (slot-definition-name slot)))
        (setf (slot-value new-struct slot-name)
          (deep-copy (slot-value struct slot-name)))))
    new-struct))

Use it in the same way you would use copy-list--ie, (deep-copy my-lisp-object) -> my-lisp-object-copy. Note however, that this method is only one of several required, since deep-copy needs to recurse over the objects in the structure’s slots, the objects within those objects, etc, until the bottommost immutable objects are reached. These other methods are included in the post at https://codereview.stackexchange.com/questions/156392/generic-copy-function if needed. (Note also, that I’ve changed the name of the methods to deep-copy from ucopy—ie, universal copy). Good luck!

Another approach is to write your own copy function for a structure type, if you are not happy with the one automatically generated. In order to do so, you first have to tell the defstruct macro to not create the copy function automatically.

(defstruct (foo (:copier nil))
  (arr (make-array 10 :initial-element 0)))
;; now you can write your custom copy-foo function
(defun copy-foo (original)
  (make-foo
    :arr (copy-seq (foo-arr original))))
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top