Common Lisp の特別な変数だけがアンバインドできると言われています。すべてのレキシカル変数のデフォルト値はnil
. クラススロットはクロージャーのようなものに存在すると思っていましたが、明らかに存在しません。
パラメータなしで CLOS スロットを定義し:initform
(いずれにせよバインドされることを期待してnil
)、インスタンスの作成時に値を指定しないと、バインドされていないスロットを持つインスタンスが取得されます。なぜそうなのですか?便利ではありません。
Common Lisp の特別な変数だけがアンバインドできると言われています。すべてのレキシカル変数のデフォルト値はnil
. クラススロットはクロージャーのようなものに存在すると思っていましたが、明らかに存在しません。
パラメータなしで CLOS スロットを定義し:initform
(いずれにせよバインドされることを期待してnil
)、インスタンスの作成時に値を指定しないと、バインドされていないスロットを持つインスタンスが取得されます。なぜそうなのですか?便利ではありません。
これは、オンデマンドでスロット値を計算する場合など、値が 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))
ミックスインクラスを作成します。
(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