如何使用 metaclass 使 class 的实例继承自特定的 superclass
How to make the instances of a class using a metaclass inherit from a specific superclass
我正在尝试为普通 lisp 实现 json 序列化 API。为此,我定义了一个名为 json-class
的元 class。这个 metaclass 定义了插槽选项 :ignore
用于忽略对象的特定插槽。由于我在序列化过程中使用 yason,我想将方法 yason:encode-slots
专门用于 classes 中使用元 class json-class
的每个对象。我能想到的实现此目的的唯一方法是使所有对象从 json-object
类型的 json-class
实例化,可用于专门化方法。
我试图复制的行为与 MOP 已经实现的行为相同,包括每个 class 使用 standard-class
生成类型为 standard-object
.[=19= 的对象]
(defpackage :so (:use :closer-common-lisp))
(in-package :so)
;; Define a metaclass named json-class.
;; It inherits from a standard-class
(defclass json-class (standard-class) ())
专精 VALIDATE-SUPERCLASS
(see also VALIDATE-SUPERCLASS explained).
(defmethod validate-superclass ((j json-class) (s standard-class)) t)
然后定义基数json-object
。
(defclass json-object () () (:metaclass json-class))
例如:
(class-of (make-instance 'json-object))
#<JSON-CLASS SO::JSON-OBJECT>
返回的对象是 json-object
,json-class
的实例,standard-class
的子类。
如果你查看 SBCL 的源代码,你会发现它在 shared-initialize
:[=24 的直接超级class 列表中添加了 standard-object
=]
(setq direct-superclasses
(or direct-superclasses
(list (if (funcallable-standard-class-p class)
*the-class-funcallable-standard-object*
*the-class-standard-object*))))
如果您希望将 class 隐式添加到直接 superclasses 列表中,最好在 shared-initialize
上的 :around
方法中执行此操作或 initialize-instance
.
另一种选择是将 compute-class-precedence-list
特化为,例如:
(cons my-superclass (call-next-method))
这就是 An existing JSON MOP library 所做的。
编辑:
我认为乱用 compute-class-precedence-list
来添加 superclasses 是未定义的行为,尽管它通常有效。我认为最好的解决方案是为 shared-initialize
或 initialize-instance
编写一个 :around
方法,首先检查(使用 subclassp
)您的 class 是否已经在继承链,没有则添加。
我正在尝试为普通 lisp 实现 json 序列化 API。为此,我定义了一个名为 json-class
的元 class。这个 metaclass 定义了插槽选项 :ignore
用于忽略对象的特定插槽。由于我在序列化过程中使用 yason,我想将方法 yason:encode-slots
专门用于 classes 中使用元 class json-class
的每个对象。我能想到的实现此目的的唯一方法是使所有对象从 json-object
类型的 json-class
实例化,可用于专门化方法。
我试图复制的行为与 MOP 已经实现的行为相同,包括每个 class 使用 standard-class
生成类型为 standard-object
.[=19= 的对象]
(defpackage :so (:use :closer-common-lisp))
(in-package :so)
;; Define a metaclass named json-class.
;; It inherits from a standard-class
(defclass json-class (standard-class) ())
专精 VALIDATE-SUPERCLASS
(see also VALIDATE-SUPERCLASS explained).
(defmethod validate-superclass ((j json-class) (s standard-class)) t)
然后定义基数json-object
。
(defclass json-object () () (:metaclass json-class))
例如:
(class-of (make-instance 'json-object))
#<JSON-CLASS SO::JSON-OBJECT>
返回的对象是 json-object
,json-class
的实例,standard-class
的子类。
如果你查看 SBCL 的源代码,你会发现它在 shared-initialize
:[=24 的直接超级class 列表中添加了 standard-object
=]
(setq direct-superclasses
(or direct-superclasses
(list (if (funcallable-standard-class-p class)
*the-class-funcallable-standard-object*
*the-class-standard-object*))))
如果您希望将 class 隐式添加到直接 superclasses 列表中,最好在 shared-initialize
上的 :around
方法中执行此操作或 initialize-instance
.
另一种选择是将 compute-class-precedence-list
特化为,例如:
(cons my-superclass (call-next-method))
这就是 An existing JSON MOP library 所做的。
编辑:
我认为乱用 compute-class-precedence-list
来添加 superclasses 是未定义的行为,尽管它通常有效。我认为最好的解决方案是为 shared-initialize
或 initialize-instance
编写一个 :around
方法,首先检查(使用 subclassp
)您的 class 是否已经在继承链,没有则添加。