CLOSオブジェクトを浅い方法で複製する方法を探しているので、作成されたオブジェクトは各スロットで同じ値を持つ同じタイプになりますが、新しいインスタンスになります。私が見つけた最も近いものは、構造体に対してこれを行う標準関数 copy-structure です。
4 に答える
一般に、CLOS オブジェクトをコピーするための標準的な定義済みの方法はありません。正しいセマンティクスはクラスごと、アプリケーションごとに異なるため、任意のオブジェクトに対して(少なくとも)ほとんどの場合正しいことを行う合理的なデフォルトのコピー操作を提供することは、可能であれば簡単なことではありません。MOP が提供する拡張された可能性は、そのようなデフォルトを提供することをさらに困難にします。また、ガベージ コレクション言語である CL では、オブジェクトのコピーは、パラメータとして渡される場合や返される場合など、あまり頻繁には必要ありません。したがって、必要に応じてコピー操作を実装することが、おそらく最もクリーンなソリューションです。
そうは言っても、これが私のスニペットファイルの1つで見つけたもので、あなたが望むことをするかもしれません:
(defun shallow-copy-object (original)
(let* ((class (class-of original))
(copy (allocate-instance class)))
(dolist (slot (mapcar #'slot-definition-name (class-slots class)))
(when (slot-boundp original slot)
(setf (slot-value copy slot)
(slot-value original slot))))
copy))
と の MOP サポートが必要にclass-slots
なりslot-definition-name
ます。
(私はおそらく古い cll スレッドからこれを採用しましたが、覚えていません。このようなものは本当に必要ではなかったので、まったくテストされていません。)
次のように使用できます (CCL でテスト済み):
CL-USER> (defclass foo ()
((x :accessor x :initarg :x)
(y :accessor y :initarg :y)))
#<STANDARD-CLASS FOO>
CL-USER> (defmethod print-object ((obj foo) stream)
(print-unreadable-object (obj stream :identity t :type t)
(format stream ":x ~a :y ~a" (x obj) (y obj))))
#<STANDARD-METHOD PRINT-OBJECT (FOO T)>
CL-USER> (defparameter *f* (make-instance 'foo :x 1 :y 2))
*F*
CL-USER> *f*
#<FOO :x 1 :y 2 #xC7E5156>
CL-USER> (shallow-copy-object *f*)
#<FOO :x 1 :y 2 #xC850306>
これは、danlei によって提出された関数のわずかに異なるバージョンです。ずいぶん前に書いていて、たまたまこの記事にたどり着きました。完全には思い出せない理由で、これはコピー後に REINITIALIZE-INSTANCE を呼び出します。この関数に追加のinitargsを渡すことで、新しいオブジェクトにいくつかの変更を加えることができると思います
例えば
(copy-instance *my-account* :balance 100.23)
これは、「標準オブジェクト」であるオブジェクトに対する汎用関数としても定義されています。どちらが正しいかもしれないし、そうでないかもしれません。
(defgeneric copy-instance (object &rest initargs &key &allow-other-keys)
(:documentation "Makes and returns a shallow copy of OBJECT.
An uninitialized object of the same class as OBJECT is allocated by
calling ALLOCATE-INSTANCE. For all slots returned by
CLASS-SLOTS, the returned object has the
same slot values and slot-unbound status as OBJECT.
REINITIALIZE-INSTANCE is called to update the copy with INITARGS.")
(:method ((object standard-object) &rest initargs &key &allow-other-keys)
(let* ((class (class-of object))
(copy (allocate-instance class)))
(dolist (slot-name (mapcar #'sb-mop:slot-definition-name (sb-mop:class-slots class)))
(when (slot-boundp object slot-name)
(setf (slot-value copy slot-name)
(slot-value object slot-name))))
(apply #'reinitialize-instance copy initargs))))