2012-06-16 23 views

cevap

10

Genel olarak CLOS nesnelerini kopyalamak için standart önceden tanımlanmış bir yol yoktur. Mümkünse, mümkün olan en doğru olanı, keyfi nesneler için doğru olanı yapan makul bir varsayılan kopyalama işlemi sağlamak, eğer mümkün ise, sınıftan sınıfa ve uygulamadan uygulamaya doğru doğru semantikler değiştiği için önemsiz değildir. MOP'un sağladığı genişletilmiş olanaklar, böyle bir varsayılanı sağlamak için daha da zorlaştırır. Ayrıca, CL'de, bir çöp toplama dili olmak, nesnelerin kopyalanmasına gerçekten çok ihtiyaç duyulmamaktadır, örn. Parametre olarak veya iade edildiğinde. Dolayısıyla, kopyalama işlemlerinizi gerektiği gibi uygulamak muhtemelen en temiz çözüm olacaktır.

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

Sen class-slots ve slot-definition-name bazı MOP desteğine ihtiyaç duyacaktır: Burada söyleniyor

Ne istediğini yapmak olabilir benim pasajı dosyalarından birinde bulunabilir budur.

(muhtemelen an old c.l.l thread bu benimsemiş, ama ben gerçekten böyle bir şey ihtiyacım olmadı, bu yüzden tamamen denenmemiş olduğunu hatırlamıyorum..)

Sen (CCL ile test) bu gibi kullanabilirsiniz:

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

Yuva bağlı veya bağlı değilse, bir sınama eklemek yararlı olabilir. Ardından, yuvaya bağlıysa, yalnızca yuva değerine erişin. –

+1

Haklısınız - Testi ekledim. Teşekkürler! – danlei

+1

İlan edildiği şekilde çalışır. Burada daha çok veya daha az taşınabilir şekilde çalışması gerektiğini bir ithalat beyanı var: '(: \t # + dan-ithalat-gölgeleme openmcl-yerli-ipler #: CCL \t # + cmu #: pcl \t # + SBCL #: sb-pCL \t # + lispworks #: hCl \t # + allegro #: paspas \t # + clisp #: Pl \t #: sınıf yuva #: yuva çözünürlüklü-ad) '. – Inaimathi

4

İşte danlei tarafından sunulan işlevin biraz farklı bir versiyonu. Bunu bir süre önce yazdım ve bu yazıya rastladım. Tamamen hatırlamadığım nedenlerden dolayı, kopyalamadan sonra REINITIALIZE-INSTANCE. Ben düşünün

gibi ek initargs'ları ileterek yeni nesnede bazı değişiklikler yapabilirsiniz.

(copy-instance *my-account* :balance 100.23) 

Bu, ayrıca 'standart nesne' olan nesneler üzerinde genel işlev olarak tanımlanır. Yapılması gereken doğru şey olabilir veya olmayabilir.

(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

Tam olarak aradığım şey; Common Lisp'de bu varsayılan olarak mevcut olmadığına şaşırdım. – MicroVirus

İlgili konular