Common LISP:将(未知)结构对象转换为 plist?

eng*_*erX 2 common-lisp

(defstruct (mydate (:constructor make-mydate (year month day)))
  (year 1970)
  (month 1)
  (day 1))

 (defvar *date1* (make-mydate 1992 1 1))
Run Code Online (Sandbox Code Playgroud)

问题更普遍,但说我想将像date1这样的对象转换为“文档”,我可以坚持到数据库(例如 mongoDB,使用包 cl-mongo)。所以我写

(defun mydate->document (mydate)
   (cl-mongo:$ (cl-mongo:$ "year" (mydate-year mydate))
               (cl-mongo:$ "month" (mydate-month mydate))
               (cl-mongo:$ "day" (mydate-day mydate))))

REPL--> (mydate->doc *date1*)
kv-container : #(#S(CL-MONGO::PAIR :KEY year :VALUE 1992)
                 #S(CL-MONGO::PAIR :KEY month :VALUE 1)
                 #S(CL-MONGO::PAIR :KEY day :VALUE 1))
Run Code Online (Sandbox Code Playgroud)

但是,我可以不必写下结构的所有字段,而是以编程方式获取它们的名称和值吗?毕竟,我的 lisp 运行时可以做到这一点:

REPL--> (describe *date1*)
#S(MYDATE :YEAR 1992 :MONTH 1 :DAY 1)
  [structure-object]

Slots with :INSTANCE allocation:
YEAR   = 1992
MONTH  = 1
DAY    = 1
Run Code Online (Sandbox Code Playgroud)

另一方面,我在任何书中都没有找到任何相关内容,并且我注意到库 cl-json 无法将结构转换为 JSON 格式(即使它确实转换了列表和 CLOS 对象)。我想如果有一个函数将结构体转换为 plist ,问题就会解决。

sds*_*sds 5

您正在寻找的称为Meta-Object ProtocolCommon lisp 开创了 MOP,但只针对 CLOS 对象,不针对defstruct对象。一些 CL 实现支持defstructMOP,但不是全部,您可以使用以下方法检查:

(defstruct s a)
(slot-definition-initargs (car (class-direct-slots (find-class 's)))) 
Run Code Online (Sandbox Code Playgroud)


Rai*_*wig 5

没有便携的方式。

实现方式不同。可能大多数人都有办法访问插槽的名称。我不清楚为什么标准中缺少这样的功能。

例如 LispWorks 有:

(structure:structure-class-slot-names (find-class 'some-structure-class))
Run Code Online (Sandbox Code Playgroud)

也许某处已经有一个兼容性库。将元对象协议功能用于 CLOS 也用于结构类是有意义的。

SBCL:

* (sb-mop:class-slots (find-class 'foo))

(#<SB-PCL::STRUCTURE-EFFECTIVE-SLOT-DEFINITION A>
 #<SB-PCL::STRUCTURE-EFFECTIVE-SLOT-DEFINITION B>)

* (mapcar 'sb-mop:slot-definition-name *)

(A B)
Run Code Online (Sandbox Code Playgroud)