Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/oop/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Oop 对象作为lisp中自身的参数_Oop_Lisp_Common Lisp_Clos_Object Initialization - Fatal编程技术网

Oop 对象作为lisp中自身的参数

Oop 对象作为lisp中自身的参数,oop,lisp,common-lisp,clos,object-initialization,Oop,Lisp,Common Lisp,Clos,Object Initialization,在Python中,我希望这样做: class foo: def __init__(self): self.x = self 否则,现在对象本身就是一个参数。如何使用common lisp进行此操作 (defclass mn () ((pai :accessor mn-pai :initarg :pai :initform self))) CLOS没有“this”或“self”的概念,因为通过使用泛型函数,正在处理的任何实

在Python中,我希望这样做:

class foo:
    def __init__(self):
        self.x = self
否则,现在对象本身就是一个参数。如何使用common lisp进行此操作

(defclass mn ()
  ((pai   :accessor mn-pai
          :initarg :pai
          :initform self)))

CLOS没有“this”或“self”的概念,因为通过使用泛型函数,正在处理的任何实例都作为参数传递

因此,以访问器
mn pai
为例:

(setf instance (make-instance 'mn))
(mn-pai instance 1)
这里,
实例
作为参数传递给访问器

如果您创建了一个方法:

(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))
(defclass mn2 ()
  ((pai   :accessor mn2-pai)))
那么,在一个普通的基于类的系统中,你会把这个方法放在哪里呢?在实用课上?这是一个“mn”类方法吗?这有点违背了现成的分类

现在考虑:

(defmethod inc-both (an-mn another-mn amount)
  (incf (mn-pai an-mn) amount)
  (incf (mn-pai another-mn) amount))
(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值
是CLO的基本访问器,并且两个类都有一个名为
pai
的slot。但是,这样就不能调用访问器函数。而是直接设置插槽。可能不是你想要的。当然,这些名字是巧合。除了相似的名称和共享的插槽名称之外,这些类之间没有任何关系

但你可以这样做:

(defmethod inc-both ((mn an-mn) (mn2 another-mn) amount)
  (incf (mn-pai an-mn) amount)
  (incf (mn-pai2 another-mn) amount))
这是因为运行时将根据参数的类型进行调度。我们“知道”
另一个mn
mn2
的一个实例,因为我们告诉系统,当我们限定参数时,它必须是

但是,您可以再次看到,在基于类的系统中,这种方法没有“位置”。我们通常只创建某种实用程序类并将其固定在其中,或者在全局命名空间中创建一个常规函数

虽然CLOS有类,但它实际上不是一个基于类的系统


这在多继承场景(CLOS支持)中也会出现。那么谁是“自我”呢?

DEFCLASS
插槽描述中,不能引用对象本身。但是可以编写实例初始化的方法。这与您的Python示例类似

我们班:

? (defclass foo ()
    ((bar :accessor foo-bar :initarg :foo)))
#<STANDARD-CLASS FOO>
或通过
(设置插槽值)
设置插槽


如您所见,该实例的槽
已设置为实例本身。

请注意,
initform
defclass
的词法上下文中计算,但在
make instance
的动态上下文中计算。这允许您定义一个名为
*This*
的特殊变量(您可以使用
This
,但这可能会造成混淆),并在初始化对象时使用它

(defvar *this*)
为可能引用此**的类定义一个mixin:

(defclass knows-this () ())

(defmethod shared-initialize :around ((object knows-this) slot-names &rest args)
  (declare (ignore args))
  (let ((*this* object))
    (call-next-method)))
例如:

(defclass foo (knows-this)
  ((myself :initform *this*)))

(describe (make-instance 'foo))

#<FOO {100AC6EF13}>
  [standard-object]

Slots with :INSTANCE allocation:
  MYSELF                         = #<FOO {100AC6EF13}>
(def类foo(知道这一点)
((我自己:initform*this*))
(描述(使实例为“foo”)
#
[标准对象]
插槽:实例分配:
我自己=#

CLOS中的运行时调度不是基于类型,而是基于类。分派参数的顺序错误。它也不“知道”一个对象的类,因为有人告诉它,但因为对象携带着它的类。对于
inc两者
,在类上分派与否没有区别。
(defclass foo (knows-this)
  ((myself :initform *this*)))

(describe (make-instance 'foo))

#<FOO {100AC6EF13}>
  [standard-object]

Slots with :INSTANCE allocation:
  MYSELF                         = #<FOO {100AC6EF13}>