有一个通用方法,比如 incx
. incx
有两个版本.一种专攻类型 a
,还有一个专门针对类型 b
.类型 b
是 a
的子类.你得到一个类型为 b
的对象,派生类型 - 但您想调用专门用于类型 a
的方法.如果还没有专门用于类型 b
的同名方法,您可以轻松地做到这一点。 ,不过唉,居然有这样的方法。
那么如何调用专用于类型 a
的方法?在这种情况下?
(defclass a () ((x :accessor x :initform 0)))
(defclass b (a) ((y :accessor y :initform 0)))
(defgeneric inc (i))
(defmethod inc ((i a)) (incf (x i)))
(defmethod inc ((i b)) (incf (y i)))
(defvar r (make-instance 'b))
正如 CLOS 所 promise 的,这调用了最专业的方法:
* (inc r)
* (describe r)
..
Slots with :INSTANCE allocation:
X = 0
Y = 1
但是在这种特殊情况下,(不是一般情况下)我想要的是访问不太专业的版本。像这样说:
(inc (r a)) ; crashes and burns of course, no function r or variable a
(inc a::r) ; of course there is no such scoping operator in CL
我看到了
call-next-method
函数可以从一个专门的方法中使用来获得下一个不那么专门的方法,但这不是这里想要的。在删除的代码中,我确实需要类似于
call-next-method
的内容。 ,但用于调用补充方法。我们不需要在下一个不太专业的类中调用同名的方法,而是需要调用它的补充方法,它具有不同的名称。补充方法也是专门的,但调用这个专门的版本不起作用 - 与 call-next-method
的原因大致相同。可能被包括在内。专用于父类(super class)的所需方法并不总是具有相同的名称。(call-next-method my-complement) ; doesn't work, thinks my-complement is an arg
这是另一个例子 .
有一个描述电子特性的基类和一个描述“奇怪电子”特性的派生类。专门针对奇怪电子的方法希望调用专门针对电子的方法。为什么?因为这些方法为程序做了正常的电子部分工作。奇怪电子的非电子部分几乎是微不足道的,或者更确切地说,如果它没有复制电子代码:
(defgeneric apply-velocity (particle velocity))
(defgeneric flip-spin (particle))
;;;; SIMPLE ELECTRONS
(defclass electron ()
((mass
:initform 9.11e-31
:accessor mass)
(spin
:initform -1
:accessor spin)))
(defmacro sq (x) `(* ,x ,x))
(defmethod apply-velocity ((particle electron) v)
;; stands in for a long formula/program we don't want to type again:
(setf (mass particle)
(* (mass particle) (sqrt (- 1 (sq (/ v 3e8)))))))
(defmethod flip-spin ((particle electron))
(setf (spin particle) (- (spin particle))))
;;;; STRANGE ELECTRONS
(defclass strange-electron (electron)
((hidden-state
:initform 1
:accessor hidden-state)))
(defmethod flip-spin ((particle strange-electron))
(cond
((= (hidden-state particle) 1)
(call-next-method)
;; CALL ELECTRON'S APPLY-VELOCITY HERE to update
;; the electron. But how???
)
(t nil)))
;; changing the velocity of strange electrons has linear affect!
;; it also flips the spin without reguard to the hidden state!
(defmethod apply-velocity ((particle strange-electron) v)
(setf (mass particle) (* (/ 8 10) (mass particle)))
;; CALL ELECTRON'S SPIN FLIP HERE - must be good performance,
;; as this occurs in critical loop code, i.e compiler needs to remove
;; fluff, not search inheritance lists at run time
)
这一切都归结为一个简单的问题:
如果定义了更专业的方法,如何调用不太专业的方法?
最佳答案
我更喜欢这里的显式方法:
(defun actually-inc-a (value) (incf (x value)))
(defun actually-inc-b (value) (incf (y value)))
(defmethod inc ((object a)) (actually-inc-a object))
(defmethod inc ((object b)) (actually-inc-b object))
即,将要共享的实现部分放入单独的函数中。
(defun apply-velocity-for-simple-electron (particle v)
(setf (mass particle) (* (mass particle) (sqrt (- 1 (sq (/ v 3e8)))))))
(defun flip-spin-for-simple-electron (particle)
(setf (spin particle) (- (spin particle))))
(defmethod apply-velocity ((particle electron) v)
(apply-velocity-for-simple-electron particle v))
(defmethod flip-spin ((particle electron))
(flip-spin-for-simple-electron particle))
(defmethod apply-velocity ((particle strange-electron) v)
(setf (mass particle) (* (/ 8 10) (mass particle)))
(flip-spin-for-simple-electron particle))
(defmethod flip-spin ((particle strange-electron))
(when (= (hidden-state particle) 1)
(call-next-method)
(apply-velocity-for-simple-electron particle #| Hu? What's the V here? |#)))
鉴于我对电子一无所知,无论是普通的还是奇怪的,旋转的与否,我真的想不出这些基本辅助函数的有意义的名称。但除此之外...
关于inheritance - CLOS:如何调用一个不太具体的方法?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35171694/