Common Lisp 中 CLOS 对象的向量

nat*_*nvy 3 lisp common-lisp clos

我遇到了无法在 Common Lisp (SBCL 2.3.4) 中解释的奇怪行为。考虑以下测试用例:

(defclass class-a ()
  ((foobar :initarg :foobar
       :accessor foobar
       :initform '(foo bar))))

(defclass class-b ()
  ((something :initarg :something
          :accessor something)))

(defvar *instance-a* (make-instance 'class-a))
(defvar *instance-b* (make-instance 'class-b :something *instance-a*))
Run Code Online (Sandbox Code Playgroud)

如果我instance-b在 REPL 中检查,我可以看到变量something已被设置:

CL-USER> (slot-value *instance-b* 'something)
#<CLASS-A {7007C70C53}>
Run Code Online (Sandbox Code Playgroud)

但是,如果我尝试创建这些对象的一个​​简单向量,由于缺乏更好的术语,该对象似乎会“失去跟踪”其绑定:

CL-USER> (slot-value (elt #(*instance-b*) 0) 'something)
; Debugger entered on #<SB-PCL::MISSING-SLOT SOMETHING {7008E5A1E3}>

When attempting to read the slot's value (slot-value), the slot
SOMETHING is missing from the object *INSTANCE-B*.
   [Condition of type SB-PCL::MISSING-SLOT]

Restarts:
 0: [RETRY] Retry SLY mREPL evaluation request.
 1: [*ABORT] Return to SLY's top level.
 2: [ABORT] abort thread (#<THREAD "sly-channel-1-mrepl-remote-1" RUNNING {70052925C3}>)

Backtrace:
 0: ((:METHOD SLOT-MISSING (T T T T)) #<BUILT-IN-CLASS COMMON-LISP:SYMBOL> *INSTANCE-B* SOMETHING SLOT-VALUE NIL) [fast-method]
 1: (SLOT-VALUE *INSTANCE-B* SOMETHING)
 2: (SB-INT:SIMPLE-EVAL-IN-LEXENV (SLOT-VALUE (ELT #(*INSTANCE-B*) 0) (QUOTE SOMETHING)) #<NULL-LEXENV>)
 3: (EVAL (SLOT-VALUE (ELT #(*INSTANCE-B*) 0) (QUOTE SOMETHING)))
Run Code Online (Sandbox Code Playgroud)

这里发生了什么?

Rai*_*wig 9

其实这个问题与CLOS无关,而是关于如何用数据创建向量。

CL-USER 4 > #(*instance-b*)
#(*INSTANCE-B*)

CL-USER 5 > (aref #(*instance-b*) 0)
*INSTANCE-B*

CL-USER 6 > (type-of (aref #(*instance-b*) 0))
SYMBOL
Run Code Online (Sandbox Code Playgroud)

该向量不包含某个 CLOS 类的实例,而是包含一个符号。

如果我们写下像 一样的文字向量,则不会计算#((+ 1 2))子表达式。(+ 1 2)

要创建向量,请使用:(vector (+ 1 2))->#(3)

反引号表示法也适用于向量:

`#(,(+ 1 2))

 -> #(3)
Run Code Online (Sandbox Code Playgroud)

您可以使用:

(slot-value (elt `#(,*instance-b*) 0) 'something)
Run Code Online (Sandbox Code Playgroud)

或者

(slot-value (elt (vector *instance-b*) 0) 'something)
Run Code Online (Sandbox Code Playgroud)