据说,只有 Common Lisp 中的特殊变量才能解绑。对于所有词法变量,默认值为nil. 我认为类插槽存在于闭包之类的东西中,但显然它们不存在。
如果我定义了一个不带:initform参数的 CLOS 插槽(希望它们nil无论如何都会被绑定)并且在创建实例时不提供值,我将得到一个带有未绑定插槽的实例。为什么会这样?它不方便。
据说,只有 Common Lisp 中的特殊变量才能解绑。对于所有词法变量,默认值为nil. 我认为类插槽存在于闭包之类的东西中,但显然它们不存在。
如果我定义了一个不带:initform参数的 CLOS 插槽(希望它们nil无论如何都会被绑定)并且在创建实例时不提供值,我将得到一个带有未绑定插槽的实例。为什么会这样?它不方便。
对于按需计算槽值之类的事情非常方便,其中值有时可能为零。当访问一个未绑定的槽时,CLOS 通常会调用SLOT-UNBOUND泛型函数,这会发出错误信号。SLOT-UNBOUND但是,您可以专注于按需计算和存储值,而不是错误。后续访问将直接使用槽值,您可以使用SLOT-MAKUNBOUND.
您可以使用某种标记的“未绑定”值来执行此操作,但是使用内置功能非常方便。
使用示例slot-unbound:
(defclass foo ()
((bar :accessor bar)
(baz :accessor baz)))
(defmethod slot-unbound (class (instance foo) slot-name)
(declare (ignorable class))
(setf (slot-value instance slot-name) nil))
在行动:
CL-USER> (defparameter *foo* (make-instance 'foo))
*FOO*
CL-USER> (bar *foo*)
NIL
CL-USER> (setf (baz *foo*) (not (baz *foo*)))
T
CLOS 实例不是闭包
CLOS 实例通常不作为闭包实现。那会很困难。它们是一些数据结构,类似于插槽的向量。类似于 Common Lisp 的结构。CLOS 实例和结构之间的区别使其复杂化:CLOS 实例可以在运行时更改槽数,并且可以在运行时更改 CLOS 实例的类。
确保插槽具有NIL价值
使用一些高级 CLOS,您可以确保插槽具有 NIL 值。请注意,CLOS我的示例中包中的函数可能在您的 CL 中的另一个包中。
此函数查看实例的所有插槽。如果插槽未绑定,则将其设置为NIL.
(defun set-all-unbound-slots (instance &optional (value nil))
(let ((class (class-of instance)))
(clos:finalize-inheritance class)
(loop for slot in (clos:class-slots class)
for name = (clos:slot-definition-name slot)
unless (slot-boundp instance name)
do (setf (slot-value instance name) value))
instance))
我们创建一个mixin类:
(defclass set-unbound-slots-mixin () ())
该修复将在初始化对象后运行。
(defmethod initialize-instance :after ((i set-unbound-slots-mixin) &rest initargs)
(set-all-unbound-slots i nil))
示例:
(defclass c1 (set-unbound-slots-mixin)
((a :initform 'something)
b
c))
CL-USER 1 > (describe (make-instance 'c1))
#<C1 4020092AEB> is a C1
A SOMETHING
B NIL
C NIL