不同的初始化,Common Lisp

问题描述 投票:0回答:2

我可以在CL中模仿不同的构造函数吗?

为了详细说明 - 比方说,C ++,我可以根据传递的参数为同一个类创建不同的构造函数。

我可以用CLOS做到这一点吗?可能有不同的initialize-instances关键args或类似的东西?

class lisp common-lisp
2个回答
1
投票

这样做的一种方法是使用辅助初始化方法:

(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'作为辅助初始化泛型函数的位置参数,然后可以在该参数上进行调度。


0
投票

好吧,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

© www.soinside.com 2019 - 2024. All rights reserved.