Dav*_*egg 5 lisp structure common-lisp
我试图定义一个结构,其中包含我想知道的一些属性,以及基本结构不需要的任意数量的其他属性.
(defstruct (node (:type list)) label [other args here])
Run Code Online (Sandbox Code Playgroud)
我知道你可以在一个函数中做到:
(defun foo (arg1 &rest args) ...)
Run Code Online (Sandbox Code Playgroud)
有某种&rest
等价物defstruct
吗?
我只是在学习口齿不清,所以我有一种感觉,我错过了一些东西.如果没有&rest
相应的,关于我如何去做这个的任何想法?提前致谢!
在Common Lisp中,结构被认为是刚性和低级记录.他们没有花哨的动态功能.
你可以用结构做的是定义一个从另一个继承的新结构类型.有单一的继承可用.
要处理动态可扩展性,一种典型的方法是向结构添加属性列表槽.看约书亚的答案.
然后是Common Lisp Object System,它提供多重继承,您可以在运行时更改类.因此,您可以向类添加一个插槽,该类的实例会自行更新.您还可以更改对象的类,可以添加或删除插槽.但是,通常所有类的实例都将具有相同的插槽集.再次,可以看到可以添加具有属性列表的槽并用于可扩展性.
Common Lisp还有其他对象系统,可以轻松地在每个实例的基础上添加插槽.但通常使用它们通常太多了,因为它们的功能更强大.
使用CLOS和元对象协议,可以尝试隐藏它.在这里我使用LispWorks:
我们为我们的属性定义了一个mixin类:
(defclass property-mixin ()
((plist :initform nil))
#+lispworks
(:optimize-slot-access nil))
Run Code Online (Sandbox Code Playgroud)
设置和读取属性:
(defmethod set-property ((object property-mixin) key value)
(setf (getf (slot-value object 'plist) key) value))
(defmethod get-property ((object property-mixin) key)
(getf (slot-value object 'plist) key))
Run Code Online (Sandbox Code Playgroud)
现在我们编写方法来SLOT-VALUE
接受我们的属性名称:
(defmethod (setf clos:slot-value-using-class)
(value (class standard-class) (object property-mixin) slot-name)
(declare (ignorable class))
(if (slot-exists-p object slot-name)
(call-next-method)
(progn
(set-property object slot-name value)
value)))
(defmethod clos:slot-value-using-class ((class standard-class)
(object property-mixin)
slot-name)
(declare (ignorable class))
(if (slot-exists-p object slot-name)
(call-next-method)
(get-property object slot-name)))
Run Code Online (Sandbox Code Playgroud)
例.我们定义了一个有两个槽的汽车类:
(defclass automobile (property-mixin)
((company :initarg :company)
(motor :initarg :motor))
#+lispworks
(:optimize-slot-access nil))
Run Code Online (Sandbox Code Playgroud)
现在是一个实例:
CL-USER 45 > (setf a6 (make-instance 'automobile :company :audi :motor :v6))
#<AUTOMOBILE 402005B47B>
Run Code Online (Sandbox Code Playgroud)
我们可以获得正常的插槽值:
CL-USER 46 > (slot-value c1 'motor)
:V6
Run Code Online (Sandbox Code Playgroud)
让我们写一个不存在的插槽,但是会添加到我们的属性列表中:
CL-USER 47 > (setf (slot-value a6 'seats) 4)
4
Run Code Online (Sandbox Code Playgroud)
我们可以获得价值:
CL-USER 48 > (slot-value c1 'seats)
4
Run Code Online (Sandbox Code Playgroud)
目前尚不清楚您正在寻找什么.结构的默认情况是具有固定数量的槽的记录类型,每个槽都有一个名称,并且可以通过defstruct
宏生成的函数访问.例如,一旦你完成了
(defstruct node
label)
Run Code Online (Sandbox Code Playgroud)
您可以访问node
标签node-label
并获得快速查找时间(因为它通常只是内存块的索引).现在,正如您所做的那样,您可以选择使用列表作为结构的实现,在这种情况下,node-label
它只是car
或的别名first
.
(defstruct (node (:type list))
label)
CL-USER> (make-node :label 'some-label)
(SOME-LABEL)
CL-USER> (node-label (make-node :label 'some-label))
SOME-LABEL
CL-USER> (first (make-node :label 'some-label))
SOME-LABEL
CL-USER> (car (make-node :label 'some-label))
Run Code Online (Sandbox Code Playgroud)
如果您正在寻找任意基于列表的键值对,您可能需要一个属性列表,Common Lisp包含一些便利函数.
如果您想拥有一个也包含属性列表的结构,您可以添加一个特殊的构造函数来填充该列表.例如,
(defstruct (node (:type list)
(:constructor make-node (label &rest plist)))
label
plist)
CL-USER> (make-node 'some-label :one 1 :two 2)
(SOME-LABEL (:ONE 1 :TWO 2))
CL-USER> (node-plist (make-node 'some-label :one 1 :two 2))
(:ONE 1 :TWO 2)
Run Code Online (Sandbox Code Playgroud)