CLOS 没有“this”或“self”的概念,因为通过使用泛型函数,正在执行的任何实例都作为参数传递。
所以,给定您使用访问器 mn-pai 的示例:
(setf instance (make-instance 'mn))
(mn-pai instance 1)
这里,instance 作为参数传递给访问器。
如果你创建了一个方法:
(defmethod inc-pai (an-mn amount)
(incf (mn-pai an-mn) amount))
再次,您会看到实例作为第一个参数传入。所以,总有一个明确的参数可供您使用。
现在考虑:
(defmethod inc-both (an-mn another-mn amount)
(incf (mn-pai an-mn) amount)
(incf (mn-pai another-mn) amount))
那么,在一个普通的基于类的系统中,你会把这个方法放在哪里呢?在实用程序类中?这是一个“mn”类方法吗?它有点违背现成的分类。
现在考虑:
(defclass mn2 ()
((pai :accessor mn2-pai)))
如果我们这样做:
(setf an-mn (make-instance 'mn))
(setf an-mn2 (make-instance 'mn2))
(inc-both an-mn an-mn2)
第二行会失败,因为 mn2 没有 mn-pai 访问器。
但是,这会起作用:
(defmethod inc-both2 (an-mn another-mn amount)
(incf (slot-value 'pai an-mn) amount)
(incf (slot-value 'pai another-mn) amount))
因为slot-value 是CLOS 的原始访问器,并且两个类都有一个名为pai 的槽。但是,您将无法调用访问器函数。而是直接设置插槽。可能不是你想要的。当然,这些名字是巧合。类之间没有关系,除了它们的相似名称和共享槽名称。
但是你可以这样做:
(defmethod inc-both ((mn an-mn) (mn2 another-mn) amount)
(incf (mn-pai an-mn) amount)
(incf (mn-pai2 another-mn) amount))
这是可行的,因为运行时将根据参数的类型进行调度。我们“知道”another-mn 是 mn2 的一个实例,因为我们告诉系统它必须是当我们限定参数时。
但是,同样,您可以看到在基于类的系统中,这种方法没有“位置”。我们通常只创建某种实用程序类并将它们粘贴在其中,或者在全局命名空间中添加一个常规函数。
虽然 CLOS 有类,但它并不是真正的基于类的系统。
这也出现在多继承场景中(CLOS 支持)。那么谁是“自我”呢?