在lisp中将对象作为自身的参数

Mat*_*pos 2 lisp oop common-lisp clos object-initialization

在Python中,我会这样做:

class foo:
    def __init__(self):
        self.x = self
Run Code Online (Sandbox Code Playgroud)

否则,现在该对象是其自身的参数.我怎样才能在普通的lisp中做到这一点?

(defclass mn ()
  ((pai   :accessor mn-pai
          :initarg :pai
          :initform self)))
Run Code Online (Sandbox Code Playgroud)

Rai*_*wig 7

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

我们班:

? (defclass foo ()
    ((bar :accessor foo-bar :initarg :foo)))
#<STANDARD-CLASS FOO>
Run Code Online (Sandbox Code Playgroud)

我们创建了一个:after方法initialize-instance.此通用函数由CLOS提供,其目的是初始化新实例.第一个参数是要初始化的实例.当我们创建类的实例时,Lisp系统将调用该方法foo.

使用访问者foo-bar:

? (defmethod initialize-instance :after ((object foo) &key)
    (setf (foo-bar object) object))
#<STANDARD-METHOD INITIALIZE-INSTANCE :AFTER (FOO)>
Run Code Online (Sandbox Code Playgroud)

或通过设置插槽(setf slot-value).

? (defmethod initialize-instance :after ((object foo) &key)
    (setf (slot-value object 'bar) object))
#<STANDARD-METHOD INITIALIZE-INSTANCE :AFTER (FOO)>
Run Code Online (Sandbox Code Playgroud)

请注意,我们可以使用任何名称命名实例参数:object或者甚至self.但这个名字没有语义.因为在CLOS中我们有多调度(调度可以解决多个参数并且没有默认的调度参数),所以没有self语义.

现在我们制作然后描述一个类的实例foo:

? (describe (make-instance 'foo))
#<FOO #x302000D20C0D>
Class: #<STANDARD-CLASS FOO>
Wrapper: #<CCL::CLASS-WRAPPER FOO #x302000D2B43D>
Instance slots
BAR: #<FOO #x302000D20C0D>
Run Code Online (Sandbox Code Playgroud)

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


cor*_*ump 5

请注意, 是initform在 的词法上下文中求值defclass,但在 的动态上下文中求值make-instance。这允许您定义一个名为的特殊变量*this*(您可以使用this,但这可能会令人困惑)并在初始化对象时使用它。

(defvar *this*)
Run Code Online (Sandbox Code Playgroud)

为可能引用的类定义一个混合*this*

(defclass knows-this () ())

(defmethod shared-initialize :around ((object knows-this) slot-names &rest args)
  (declare (ignore args))
  (let ((*this* object))
    (call-next-method)))
Run Code Online (Sandbox Code Playgroud)

例如:

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

(describe (make-instance 'foo))

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

Slots with :INSTANCE allocation:
  MYSELF                         = #<FOO {100AC6EF13}>
Run Code Online (Sandbox Code Playgroud)