Sto cercando un modo per clonare gli oggetti CLOS in modo superficiale, quindi l'oggetto creato sarebbe dello stesso tipo con gli stessi valori in ogni slot, ma una nuova istanza. La cosa più vicina che ho trovato è una funzione di copia della funzione standard che fa questo per le strutture.Esiste un metodo generico per clonare oggetti CLOS?
risposta
Non esiste un modo predefinito standard per copiare gli oggetti CLOS in generale. Non è banale, se possibile, fornire una ragionevole operazione di copia predefinita che faccia la cosa giusta (almeno) la maggior parte del tempo per oggetti arbitrari, poiché la semantica corretta cambia da una classe all'altra e dall'applicazione all'applicazione. Le estese possibilità offerte dal MOP rendono ancora più difficile fornire tale impostazione predefinita. Inoltre, in CL, essendo un linguaggio garbage collection, la copia di oggetti non è realmente necessaria molto spesso, ad es. quando passato come parametri o essere restituito. Quindi, implementare le operazioni di copia secondo necessità sarebbe probabilmente la soluzione più pulita.
Detto questo, qui è quello che ho trovato in uno dei miei file dei frammenti, che potrebbe fare quello che vuoi:
(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))
Avrete bisogno di qualche supporto MOP per class-slots
e slot-definition-name
.
(probabilmente adottato questo da an old c.l.l thread, ma non riesco a ricordare non ho mai veramente avuto bisogno di qualcosa di simile, quindi è assolutamente non testato..)
è possibile utilizzarlo in questo modo (testato con 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>
Ecco una versione leggermente diversa della funzione presentata da danlei. L'ho scritto qualche tempo fa e sono incappato in questo post. Per motivi che non ricordo completamente, questo chiama REINITIALIZE-INSTANCE dopo la copia. I penso è così è possibile apportare alcune modifiche al nuovo oggetto passando l'initargs aggiuntivo a questa funzione
ad es.
(copy-instance *my-account* :balance 100.23)
Questo è anche definito come funzione generica su oggetti che sono "oggetti standard". Quale potrebbe o potrebbe non essere la cosa giusta da fare.
(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))))
Esattamente quello che stavo cercando; Sono stato sorpreso che questo non esiste di default in Common Lisp. – MicroVirus
- 1. Esiste un modo generico per sincronizzare un metodo asincrono?
- 2. override un metodo generico per un generico in Java
- 3. Esiste un metodo di scambio generico nel framework?
- 4. GetMethod per metodo generico
- 5. Esiste un TimeZoneInfo generico per l'Europa centrale?
- 6. Perché è un metodo generico scelto quando esiste un non generico?
- 7. Java: metodo generico per Enum
- 8. Falsificare un metodo generico FakeItEasy
- 9. Come rendere un metodo generico che prendono un tipo generico
- 10. C#: esiste un modo generico per inoltrare una chiamata di metodo a un altro oggetto (con la stessa interfaccia)?
- 11. Come scrivere un metodo Java generico e confrontare due variabili del tipo generico all'interno del metodo?
- 12. Esiste un metodo "HasNext" per un IEnumerator?
- 13. Uso generico Metodo FromEvent
- 14. Python per clonare un repository git
- 15. Esiste un metodo generico foreach in Delphi per che può essere chiamata con funzione anonima
- 16. Esiste un metodo Groovy per sincronizzare un metodo?
- 17. Esiste un generico generatore di codici Maven?
- 18. Cosa significa clonare() un oggetto?
- 19. Esiste un costo per metodo per l'istanziazione degli oggetti in Java?
- 20. Esiste un metodo per trovare gli attributi modificati per gli oggetti?
- 21. metodo generico in Java senza argomento generico
- 22. Esiste un metodo CapitalizeFirstLetter?
- 23. Esiste un tipo generico che implementa QueryInterface?
- 24. metodo generico senza parametro
- 25. Sun CodeModel metodo generico
- 26. come lanciare un tipo generico per adattare un altro metodo generico
- 27. C# Abstract Metodo generico
- 28. Esiste un tale metodo per chiamare "getBackgroundColor"?
- 29. Esiste un metodo inverso per `Array # include?`?
- 30. Elenco generico di oggetti generici
Potrebbe essere utile aggiungere un test se uno slot è vincolato o meno. Quindi accedere solo al valore dello slot, se lo slot è vincolato. –
Hai ragione - Ho aggiunto il test. Grazie! – danlei
Funziona come pubblicizzato. Ecco una dichiarazione di importazione che dovrebbe farlo funzionare in modo più o meno portabile: '(: shadowing-import-da \t # + OpenMCL-native-threads #: CCL \t # + CMU #: PCL \t # + SBCL #: sb-pcl \t # + lispworks #: HCl \t # + allegro #: scopa \t # + clisp #: clos \t #: cLASS-slots #: slot-definition-name) '. – Inaimathi