如何正确指定可调向量的元素类型

时间:2019-04-04 23:09:01

标签: types common-lisp adjustable-array

以下是旨在用作(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)

为什么按'a不会产生类型错误,这将如何解决?

2 个答案:

答案 0 :(得分: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

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

答案 1 :(得分: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所说,该类型主要用于帮助编译器有机会对数组(位向量,字符串等)使用专门的表示形式。

integer可以是大数字,这就是为什么升级后的元素类型为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)))