4

我正在尝试为 common lisp 实现 json 序列化 API。为了实现这一点,我定义了一个名为json-class. 这个元类定义了:ignore用于忽略对象的特定槽的槽选项。由于我使用 yason 进行序列化过程,因此我想将该方法专门yason:encode-slots用于使用 metaclass 的类的每个对象json-class。我能想到的唯一方法是使所有对象从可用于专门化方法json-class的类型实例化。json-object我试图复制的行为与 MOP 已经实现的行为相同,该行为包含在每个类中,使用standard-class生成类型的对象standard-object

4

2 回答 2

2

使用更接近拖把

(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(另请参阅VALIDATE-SUPERCLASS 解释)。

(defmethod validate-superclass ((j json-class) (s standard-class)) t)

然后定义 base 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

于 2019-07-26T15:31:39.440 回答
1

如果您查看 SBCL 的源代码,您会发现它添加standard-object到 内部的直接超类列表中shared-initialize

         (setq direct-superclasses
               (or direct-superclasses
                   (list (if (funcallable-standard-class-p class)
                             *the-class-funcallable-standard-object*
                             *the-class-standard-object*))))

如果您希望将一个类隐式添加到直接超类列表中,最好在or的:around方法中执行此操作。shared-initializeinitialize-instance

另一种选择是专注compute-class-precedence-list于,例如:

(cons my-superclass (call-next-method))

这就是现有的 JSON MOP 库所做的。

编辑:

我认为compute-class-precedence-list添加超类是未定义的行为,尽管它通常有效。我相信最好的解决方案是编写一个:around方法,或者shared-initialize首先initialize-instance检查(使用subclassp)你的类是否已经在继承链中,如果没有,则添加它。

于 2020-07-28T17:41:49.030 回答