在 Common Lisp 中,结构被认为是严格的低级记录。他们没有花哨的动态功能。
你可以用结构做的是定义一个新的结构类型,它继承自另一个结构类型。有单继承可用。
为了处理动态可扩展性,一种典型的方法是在结构中添加一个属性列表槽。见约书亚的回答。
然后是 Common Lisp 对象系统,它提供多重继承,您可以在运行时更改类。因此,您可以向一个类添加一个插槽,并且该类的实例会自行更新。您还可以更改对象的类,并且可能会添加或删除插槽。尽管如此,通常一个类的所有实例都将具有相同的插槽集。同样,人们看到可以添加带有属性列表的插槽并将其用于可扩展性。
Common Lisp 还有其他对象系统,可以轻松地在每个实例基础上添加插槽。但是仅仅为此使用它们通常是太多了,因为它们的功能要强大得多。
使用 CLOS 和元对象协议,可以尝试隐藏它。我在这里使用 LispWorks:
我们为我们的属性定义了一个 mixin 类:
(defclass property-mixin ()
((plist :initform nil))
#+lispworks
(:optimize-slot-access nil))
设置和读取属性:
(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))
现在我们编写方法来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)))
例子。我们定义了一个带有两个插槽的汽车类:
(defclass automobile (property-mixin)
((company :initarg :company)
(motor :initarg :motor))
#+lispworks
(:optimize-slot-access nil))
现在举个例子:
CL-USER 45 > (setf a6 (make-instance 'automobile :company :audi :motor :v6))
#<AUTOMOBILE 402005B47B>
我们可以得到一个正常的槽值:
CL-USER 46 > (slot-value c1 'motor)
:V6
让我们写入一个不存在但将被添加到我们的属性列表中的插槽:
CL-USER 47 > (setf (slot-value a6 'seats) 4)
4
我们可以取回值:
CL-USER 48 > (slot-value c1 'seats)
4