我可以在CL中模仿不同的构造函数吗?
为了详细说明 - 比方说,C ++,我可以根据传递的参数为同一个类创建不同的构造函数。
我可以用CLOS做到这一点吗?可能有不同的initialize-instance
s关键args或类似的东西?
这样做的一种方法是使用辅助初始化方法:
(defclass myclass ()
((s1 :initarg :s1 :accessor s1)))
(defgeneric initialize-myclass (dispatch class &key))
(defmethod initialize-instance :after ((c myclass) &rest args &key (dispatch 'normal)
&allow-other-keys)
(apply #'initialize-myclass dispatch c args))
(defmethod initialize-myclass ((dispatch (eql 'normal)) (class myclass) &key))
(defmethod initialize-myclass ((dispatch (eql 'special)) (class myclass)
&key x &allow-other-keys)
(print x))
现在你可以说
(make-instance 'myclass :dispatch 'special ...)
例如。请注意,这不一定是一种很好的方法,但它确实有效,而且我已经使用过了。请注意,我可能有关键字参数默认错误:我永远不记得你需要说&allow-other-keys
和你不在哪里,以及正确的地方说它是什么。
这里的基本问题是我们需要一个额外的东西来调度:initialize-instance
可以在被定义的对象的类上调度,但这就是它可以调度的所有内容。特别是它无法在其中一个关键字参数上进行调度,因为您无法在CLOS中执行此操作。但是我们可以将其中一个关键字参数(dispatch
在这里)和'bless'作为辅助初始化泛型函数的位置参数,然后可以在该参数上进行调度。
好吧,initialize-instance
通常被定义为:after
方法,一旦实例通过make-instance
初始化,就可以运行某种后处理。您可能要做的是使用参数多态(在参数上调度),并使用不同的方法根据提供的参数初始化您的实例。请考虑以下示例:
CL-USER> (defclass my-class ()
((a :initarg :a
:accessor my-class-a)))
#<STANDARD-CLASS COMMON-LISP-USER::MY-CLASS>
CL-USER> (defmethod make-my-class ((a number))
(make-instance 'my-class :a (format nil "Look ma, a number ~a" a)))
#<STANDARD-METHOD COMMON-LISP-USER::MAKE-MY-CLASS (NUMBER) {1016445273}>
CL-USER> (defmethod make-my-class ((a string))
(make-instance 'my-class :a (format nil "Look ma, a string ~a" a)))
#<STANDARD-METHOD COMMON-LISP-USER::MAKE-MY-CLASS (STRING) {10166065C3}>
CL-USER> (make-my-class 10)
#<MY-CLASS {1016690E33}>
CL-USER> (my-class-a *)
"Look ma, a number 10"
CL-USER> (make-my-class "foo")
#<MY-CLASS {1016694CD3}>
CL-USER> (my-class-a *)
"Look ma, a string foo"
如您所见,方法make-my-class
调度其参数并相应地初始化my-class
。