为什么这个 lisp 向量没有扩展?

Sli*_*org 2 vector sbcl common-lisp

我正在尝试使用 SBCL 在 Common Lisp 中创建一个节点对象,该节点对象使用其文本元素进行初始化,然后链接到其他节点。我的函数链接应该采用节点“from_node”,获取其成员链接(应该是可变/可扩展向量)并推入节点“to_node”。

我编译 say.lisp,创建 2 个代表节点的全局变量,然后尝试链接这两个节点。我收到一个错误

这是say.lisp

(defclass node ()
  ((text
     :initarg :text)
   (links
     :initform (make-array 1 :adjustable t))))

(defun link (from_node to_node)
  (vector-push-extend to_node (slot-value from_node 'links)))
Run Code Online (Sandbox Code Playgroud)

然后在 REPL 中

* (load "say.lisp")  
T
* (defvar *x* (make-instance 'node :text "hello world"))

*X*
* (defvar *y* (make-instance 'node :text "bye world"))  

*Y*
* (link *x* *y*)

debugger invoked on a TYPE-ERROR in thread
#<THREAD "main thread" RUNNING {1003016593}>:
  The value #() is not of type (AND VECTOR (NOT SIMPLE-ARRAY)).

Type HELP for debugger help, or (SB-EXT:EXIT) to exit from SBCL.

restarts (invokable by number or by possibly-abbreviated name):
  0: [ABORT] Exit debugger, returning to top level.

(VECTOR-PUSH-EXTEND #<NODE {10031D3983}> #() NIL)
0] 
Run Code Online (Sandbox Code Playgroud)

最初我认为我正在制作一个不可变的向量,但是 ":adjustable t" 应该允许它工作。

怎么了?

Jos*_*lor 5

VECTOR-PUSH-EXTEND要求向量参数是“带有填充指针的向量”。将:adjustable t传递给make-array使其可调整,但不会为其提供填充指针。例如,没有填充指针:

CL-USER> (defparameter *x* (make-array 1 :adjustable t))
*X*
CL-USER> *x*
#(0)
CL-USER> (vector-push-extend 3 *x*)
; Evaluation aborted on #<SIMPLE-TYPE-ERROR expected-type:
                    (AND VECTOR (SATISFIES ARRAY-HAS-FILL-POINTER-P))
                    datum: #<(VECTOR T 1) {100464C57F}>>.
Run Code Online (Sandbox Code Playgroud)

使用填充指针:

CL-USER> (defparameter *x* (make-array 1 :adjustable t :fill-pointer 0))
*X*
CL-USER> *x*
#()
CL-USER> (vector-push-extend 3 *x*)
0
CL-USER> (vector-push-extend 4 *x*)
1
CL-USER> (vector-push-extend 5 *x*)
2
CL-USER> *x*
#(3 4 5)
Run Code Online (Sandbox Code Playgroud)

这是一个重要的区别,因为正如您所见,您可以拥有没有填充指针的可调整数组。这些可以调整大小,但似乎总是有与空间一样多的元素。(例如,在第一种情况下,* X *具有长度之一。你也可以有阵列将填补是不可调的指针。这将仍然允许您使用矢量推动矢量推延长,直到被填满,但之后无法调整大小。