在SBCL中使用键入的插槽读取结构

时间:2017-08-06 15:46:38

标签: arrays lisp common-lisp read-eval-print-loop sbcl

考虑这个简单的代码示例:

(defstruct test
  (:example nil :type (simple-array single-float)))

(defparameter test-struct
  (make-test :example (make-array 10 :element-type 'single-float
                                     :initial-element 1.0)))

我们可以看到,没有什么可以疯狂的,定义了一个带有单个插槽的简单结构。我们还指定:example槽是强类型,预期是单浮点数组。这里没有问题,一切正常。

现在让我们将test-struct写入文件:

(with-open-file (out "~/Desktop/out.test"
             :direction :output
             :if-exists :supersede)
  (format out "~s" test-struct))

同样,没有惊喜,我们在桌面上获得了一个很好的小文件,其中包含以下内容:

#S(TEST :EXAMPLE #(1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0))

然而,紧张开始蔓延,因为我们注意到没有任何迹象表明这个特定的文字数组应该包含单个浮点数。有了这种怀疑,让我们尝试加载这个结构:

(defparameter loaded-struct
  (with-open-file (in "~/Desktop/out.test")
    (read in nil)))

我们在这里,SBCL愉快地将我们放入调试器中:

SBCL drops into a debugger when attempting to read a typed array

问题是:有没有办法指示SBCL验证结构中的此数组插槽是否为有效类型并加载它?或者换句话说,是否可以在不诉诸构建自定义编写器和构造函数的情况下读取具有强类型槽的结构?

1 个答案:

答案 0 :(得分:7)

如果您打印对象可读

,它会起作用
(equalp test-struct
        (read-from-string 
          (with-output-to-string (o)
            (write test-struct :readably t :stream o))))
=> T ;; no error while reading the structure back

字符串是:

"#S(TEST
   :EXAMPLE #.(COERCE #(1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0)
                      '(SIMPLE-ARRAY SINGLE-FLOAT (*))))"

如果您想使用format,请在~W为T时使用*print-readably*