2012-06-16 23 views
6

私は、浅い方法でCLOSオブジェクトをクローンする方法を探しています。そのため、作成されたオブジェクトは、各スロットに同じ値を持つ同じタイプのものになりますが、新しいインスタンスになります。私が見つけた最も近いものは、構造のためにこれを行う標準関数のコピー構造です。CLOSオブジェクトを複製する一般的な方法はありますか?

答えて

10

CLOSオブジェクトを一般的にコピーするための標準的な事前定義された方法はありません。正しいセマンティクスがクラスごとに、そしてアプリケーションごとに変化するので、任意のオブジェクトのために大部分の時間(少なくとも)適切なことを行う妥当なデフォルトコピー操作を提供することは、可能であれば些細なことではありません。 MOPが提供する拡張可能性により、そのようなデフォルトを提供することはさらに困難になります。また、CLにおいて、ガベージコレクション言語であるので、オブジェクトのコピーは、非常に頻繁には必要とされない。パラメータとして渡されたとき、または返されたとき。したがって、必要に応じてコピー操作を実装することが、おそらく最もクリーンな解決策になるでしょう。言われていること

は、ここにあなたがやりたいかもしれない、私は私のスニペットファイルのいずれかで見つけたものです:

(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)) 

あなたがclass-slotsslot-definition-nameのためのいくつかのMOPのサポートが必要になります。

(私はおそらくan old c.l.l threadからこれを採用したが、私は、私は本当にこのような何かを必要としません思い出すことができないので、それは全くテストされていないのです。。)

あなたがこの(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> 
+5

スロットがバインドされているかどうかをテストするのに役立つ場合があります。次に、スロットがバインドされている場合にのみ、スロット値にアクセスします。 –

+1

あなたが正しいです - 私はテストを追加しました。ありがとう! – danlei

+1

広告されたとおりに動作します。以下は、より移植可能な方法で動作するようにするimport文です: '(:shadowing-import-from \t#openmcl-native-threads#:ccl \t#+ cmu#:pcl \t# + SBCL#:SB-PCL \t#+ lispworks番号:塩酸 \t#+アレグロ#:モップ \t#+ CLISP#:CLOS \t#:クラススロット#:スロット定義名) '。 – Inaimathi

4

ここでは、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)))) 
+1

私が探していたものとまったく同じです。私はこれがデフォルトでCommon Lispには存在しないことに驚きました。 – MicroVirus

関連する問題