如何将方法对象作为函数来调用?
Closer-mop 和clos 包都提供method-function 用于将方法对象转换为函数。但是,有没有办法在不包含另一个包的情况下做到这一点?如果不是,哪个包? (使用SBCL),但如果需要一个包,那么判别函数是怎么做的呢?
这里是一个使用find-method获取方法对象的例子。接下来的问题是如何调用要调用的方法。
(defclass a () ((x :accessor x :initform 0)))
(defgeneric inc (i))
(defmethod inc ((i a)) (incf (x i)))
(defvar r (make-instance 'a))
;; ... in a land far far away:
(defvar method-to-be-called (find-method #'inc '() '(a)))
(funcall method-to-be-called r);; crashes and burns
作为次要问题,文档说辨别函数首先尝试compute-applicable-methods-by-class 来找到方法对象,如果失败,它使用计算适用方法。为什么采用这种两层方法?假设 find-method 正在执行这种两层方法是否正确,因此最好使用 find-method ?
-- 附录 -- 在下面的评论中,Rainer Joswig 指出这种查找方法形式依赖于实现:
(find-method #'inc '() '(a))) ; works on sbcl 1.3.1
他说说明符列表应该是类并建议改为:
(find-method #'inc '() (list (find-class 'a))))
所以我想把我的类(class)放在那里:
(find-method #'inc '() (list a)) ; crashes and burns
显然 (defclass a ... ) 没有将 a 设置为一个类。事实上,它没有设置任何东西!
* (defclass a () ((x :accessor x :initform 0)))
#<STANDARD-CLASS COMMON-LISP-USER::A>
* a
... 变量 A 未绑定(bind)。
但是,这是可行的:
* (defvar ca (defclass a () ((x :accessor x :initform 0))))
CA
* (defmethod inc ((i a)) (incf (x i)))
WARNING: Implicitly creating new generic function COMMON-LISP-USER::INC.
#<STANDARD-METHOD COMMON-LISP-USER::INC (A) {1005EE8263}>
enter code here
* (find-method #'inc '() (list ca))
#<STANDARD-METHOD COMMON-LISP-USER::INC (A) {1005EE8263}>
*
所以类是 defclass 的返回值,而不是提供给 defclass 的符号的值。
最佳答案
(find-method #'inc '() '(a))
以上无效。我们需要一个类列表,而不是符号列表。
(funcall (method-function (find-method #'inc
'()
(list (find-class 'a))))
r)
由于函数 method-function
属于 MOP,许多实现都提供它,并且它在一些实现特定的包中。 CLOSER-MOP
也使其可用。
但通常情况下,如果您已经在尝试提取方法函数,那么您可能以错误的方式使用 CLOS,或者您真的知道自己在做什么...
关于methods - 如何使用标准函数调用方法对象,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35220471/