您的问题的标题听起来像是您在询问如何访问插槽,但您显示的代码似乎更像是关于调用已专门用于超类的方法。如果您正在寻找后者,您应该查看call-next-method
以及HyperSpec 中的7.6 Generic Functions and Methods。
调用“超类方法”</h2>
在 CLOS 中,方法不像其他语言那样属于类。相反,存在定义了专门方法的通用函数。对于给定的参数列表,可能有多种方法适用,但只有一种是最具体的。您可以使用 调用下一个最具体的方法call-next-method
。在下面的脚本中,有一个类FOO
和一个子类,以及一个具有专门用于和的方法BAR
的泛型函数。在专用于 的方法中,有一个调用,在这种情况下,调用专用于 的方法。FROB
FOO
BAR
BAR
call-next-method
FOO
CL-USER> (defclass foo () ())
;=> #<STANDARD-CLASS FOO>
CL-USER> (defclass bar (foo) ())
;=> #<STANDARD-CLASS BAR>
CL-USER> (defgeneric frob (thing))
;=> #<STANDARD-GENERIC-FUNCTION FROB (0)>
CL-USER> (defmethod frob ((foo foo))
(print 'frobbing-a-foo))
;=> #<STANDARD-METHOD FROB (FOO) {1002DA1E11}>
CL-USER> (defmethod frob ((bar bar))
(call-next-method)
(print 'frobbing-a-bar))
;=> #<STANDARD-METHOD FROB (BAR) {1002AA9C91}>
CL-USER> (frob (make-instance 'bar))
FROBBING-A-FOO
FROBBING-A-BAR
;=> FROBBING-A-BAR
用方法组合模拟它
您可以使用方法组合来组合适用于参数列表的方法的结果。例如,您可以a
使用方法组合定义一个方法,list
这意味着当您调用 时(a thing)
,将调用适用于参数的所有方法a
,并将它们的结果组合到一个列表中。如果您为不同类中的插槽指定不同的名称,并专门a
读取这些值的方法,您可以模拟您正在寻找的东西。这并不妨碍您也使用访问插槽的传统阅读器(例如,get-a
在以下示例中)。以下代码显示了一个示例:
(defgeneric a (thing)
(:method-combination list))
(defclass animal ()
((animal-a :initform 'a :reader get-a)))
(defmethod a list ((thing animal))
(slot-value thing 'animal-a))
(defclass dog (animal)
((dog-a :initform 'b :reader get-a)))
(defmethod a list ((thing dog))
(slot-value thing 'dog-a))
(a (make-instance 'dog))
(get-a (make-instance 'animal))
;=> A
(get-a (make-instance 'dog))
;=> B
使用拖把
这篇1998 年关于 Allegro CL 档案的帖子值得一读。听起来作者正在寻找与您正在寻找的东西相似的东西。
我需要定义一个继承行为,将超类初始化形式的字符串值与本地插槽初始化形式连接起来。例如
(defclass super()
((f :accessor f :initform "head")) (:metaclass user-class))
(defclass sub(super)
((f :accessor f :initform "tail")) (:metaclass user-class))
我想得到以下内容:
(f(make-instance'sub)) -> "head tail"
我没有在 defclass slot-descriptions 中找到一个标准选项。我想为每个元类“用户类”定义连接组合。
响应(来自 Heiko Kirschke,不是我,但也可以看到Jon White采用类似方法的响应)定义了一种新型类:
(defclass user-class (standard-class) ())
并专门clos:compute-effective-slot-definition
提供一个从类及其超类的槽定义计算的 initform:
(defmethod clos:compute-effective-slot-definition
((the-class user-class) slot-name
;; The order of the direct slots in direct-slot-definitions may
;; be reversed in other LISPs (this is code written & tested with
;; ACL 4.3):
direct-slot-definitions)
(let ((slot-definition (call-next-method))
(new-initform nil))
(loop for slot in direct-slot-definitions
as initform = (clos:slot-definition-initform slot)
when (stringp initform)
do
;; Collecting the result string could be done perhaps more
;; elegant:
(setf new-initform (if new-initform
(concatenate 'string initform " "
new-initform)
initform)))
(when new-initform
;; Since at (call-next-method) both the initform and
;; initfunction of the effective-slot had been set, both must be
;; changed here, too:
(setf (slot-value slot-definition 'clos::initform) new-initform)
(setf (slot-value slot-definition 'clos::initfunction)
(constantly new-initform)))
slot-definition))
然后它是这样使用的:
(defclass super ()
((f :accessor f :initform "head"))
(:metaclass user-class))
(defclass sub(super)
((f :accessor f :initform "tail"))
(:metaclass user-class))
(f (make-instance 'sub))
==> "head tail"
这涉及到规范未指定的 MOP 功能,因此您可能必须针对您的特定实现对其进行调整。不过,有一些 MOP 兼容层包可能会帮助您。