Common Lisp - 如何更改类的元类



这种情况一次又一次地发生在我身上:我定义了这个类,却忘记了我希望它是可函数的,或者它是Gtk小部件类,因此它的元类需要声明。然而,一旦定义好了,SBCL就不允许我更改元类(即使没有这个类的实例(。例如,评估

(defclass foo ()
  ((slot-a)))

然后添加元类并重新评估:

(defclass foo ()
  ((slot-a))
  (:metaclass gobject:gobject-class))

导致错误:

Cannot CHANGE-CLASS objects into CLASS metaobjects.
   [Condition of type SB-PCL::METAOBJECT-INITIALIZATION-VIOLATION]
See also:
  The Art of the Metaobject Protocol, CLASS [:initialization]

不幸的是,我没有一本元对象协议的艺术来检查它的内容。目前,我唯一能找到的方法就是重新启动lisp,这可能会造成很大的破坏。

由于我很快就意识到了这个错误,我不介意通过删除它来完全避开定义的类。问题:

  • 如果我已经创建了类的实例,有没有一种方法可以找到它们,使它们无效并获得GCed
  • 如何删除类?类似于函数的fmakunbound

不幸的是,我没有一本元对象协议的艺术来检查它的内容。

尽管我建议你读这本书,但你可以在网上找到一些信息。请参见示例ENSURE-CLASS-USING-CLASS

如何删除类?

您可以使用(SETF FIND-CLASS):

(setf (find-class 'foo) nil)

或者,你可以使用高级黏液检查员。在指向类名的同时调用slime-inspect-defintion。然后,你会看到这个名字。选择它时,将检查命名类的符号。然后,你可以看到这样的东西:

It names the class FOO [remove]

如果FOO只命名一个类,你可以使用更大的锤子:

(unintern 'foo)

如果我已经创建了类的实例,有没有一种方法可以找到它们,使它们无效并获得GCed?

不,只有GC具有全局视图,而且出于实际原因,它通常不会保留关于谁引用特定对象(以及如何引用(的向后引用1。没有一个类的所有实例的全局记录,除非您引入自己的(弱(哈希表来存储它们。但是,如果您保存了所有实例的记录,则可以CHANGE-CLASS它们。例如,您定义:

(defclass garbage () ())

对象中以前持有的任何引用都将被释放,GC有机会处理引用的对象实例。当另一个对象引用"垃圾"的实例时,你可以更新它。你可以不使用"垃圾",而是将旧类的实例更改为新类(名称相同,但类对象不同(。还要注意,CHANGE-CLASS是一个通用函数。


1。实现可能会提供堆遍历器。例如参见Allegro CL中的堆行走器。

相关内容

  • 没有找到相关文章

最新更新