17.5 定义方法 (Defining Methods)
到目前为止,我们借由叙述如下的东西来定义一个方法:
(defprop area t)
(setf circle-class (obj))
(setf (area circle-class)
#'(lambda (c) (* pi (expt (radius c) 2))))
(defmacro defmeth (name obj parms &rest body)
(let ((gobj (gensym)))
`(let ((,gobj ,obj))
(setf (gethash ',name ,gobj)
(labels ((next () (get-next ,gobj ',name)))
#'(lambda ,parms ,@body))))))
(defun get-next (obj name)
(some #'(lambda (x) (gethash name x))
(cdr (gethash :preclist obj))))
图 17.6 定义方法。
在一个方法里,我们可以通过给对象的 :preclist
的 cdr
获得如内置 call-next-method
方法的效果。所以举例来说,若我们想要定义一个特殊的圆形,这个圆形在返回面积的过程中印出某个东西,我们可以说:
(setf grumpt-circle (obj circle-class))
(setf (area grumpt-circle)
#'(lambda (c)
(format t "How dare you stereotype me!~%")
(funcall (some #'(lambda (x) (gethash 'area x))
(cdr (gethash :preclist c)))
c)))
这里 funcall
等同于一个 call-next-method
调用,但他..
图 17.6 的 defmeth
宏提供了一个便捷方式来定义方法,并使得调用下个方法变得简单。一个 defmeth
的调用会展开成一个 setf
表达式,但 setf
在一個 labels
表达式里定义了 next
作为取出下个方法的函数。这个函数与 next-method-p
类似(第 188 页「譯註: 11.7 節」),但返回的是我们可以调用的东西,同時作為 call-next-method
。 λ 前述两个方法可以被定义成:
(defmeth area circle-class (c)
(* pi (expt (radius c) 2)))
(defmeth area grumpy-circle (c)
(format t "How dare you stereotype me!~%")
(funcall (next) c))
顺道一提,注意 defmeth
的定义也利用到了符号捕捉。方法的主体被插入至函数 next
是局部定义的一个上下文里。
当前内容版权归 readthedocs 或其关联方所有,如需对内容或内容相关联开源项目进行关注与资助,请访问 readthedocs .