2

以下是一个旨在用作 (lifo) 堆栈或 (fifo) 队列的结构

(defstruct jvector
  (vector (make-array 0 :adjustable t :fill-pointer 0) :type (array * (*)))
  (start 0 :type (integer 0 *)))

内容范围从 jvector-start 到 jvector-vector 填充指针。我希望能够用类似的东西指定内容的元素类型

(defun create-jvector (&key (element-type t))
  (make-jvector :vector (make-array 0 :element-type element-type :adjustable t :fill-pointer 0)
                :start 0))

并用

(defun push-jvector (elt jvec)
  (vector-push-extend elt (jvector-vector jvec)))

但是,create-jvector 中的元素类型被忽略。例如,

* (defparameter v (create-jvector :element-type 'integer))
V
* v
#S(JVECTOR :VECTOR #() :START 0)
* (push-jvector 1 v)
0          ;OK result
* v
#S(JVECTOR :VECTOR #(1) :START 0)
* (push-jvector 'a v)
1          ;not OK result
* v
#S(JVECTOR :VECTOR #(1 A) :START 0)

为什么 push 'a 不会产生类型错误,什么会解决这个问题?

4

2 回答 2

6

如果你告诉MAKE-ARRAY一个元素类型,那么它将尝试分配一个节省空间的数组。实现通常支持一些变体:

例子:

CL-USER 13 > (mapcar #'upgraded-array-element-type
                     '(bit fixnum character))
((UNSIGNED-BYTE 1) (SIGNED-BYTE 64) CHARACTER)

但是对于许多类型来说,没有节省空间的数组:

CL-USER 14 > (mapcar #'upgraded-array-element-type
                     '(integer string standard-object))
(T T T)

您要求一个整数数组并得到一个通用数组:请参阅T返回的类型upgraded-array-element-type

这不是关于类型检查,而是关于要求运行时可能获得空间优化数组。

于 2019-04-05T07:56:56.610 回答
4

为什么没有类型错误

根据array-element-type数组的类型检查类型:

(defparameter w (create-jvector :element-type 'fixnum))

(array-element-type (jvector-vector v))
=> T

(array-element-type (jvector-vector w))
=> FIXNUM

将符号推送到W会导致错误。正如 jkiiski 所说,该类型主要用于帮助编译器有机会使用数组的专门表示(位向量、字符串等)。

Aninteger可以是 bignum,这就是升级后的元素类型为T

(upgraded-array-element-type 'integer)
=> T

如何解决您的问题

这是jkiiski提示的解决方案,即在结构中添加类型;这里我也直接从结构中重新定义了构造函数:

(defstruct (j2vector
             (:constructor make-jvector
                           (element-type
                            &aux
                            (start 0)
                            (vector (make-array 0
                                                :adjustable t
                                                :fill-pointer 0
                                                :element-type element-type)))))
  element-type
  vector
  (start 0 :type (integer 0)))

然后你明确地检查类型:

(defun push-jvector (elt jvec)
  (assert (typep elt (j2vector-element-type jvec)) ())
  (vector-push-extend elt (j2vector-vector jvec)))
于 2019-04-05T07:56:39.927 回答