引数&keyの内容を指定しない場合を考える
例えば
(defmethod aaa (value &key) ...)
のように&key
だけを指定して、その後の変数を記載しない場合があります。
全くの無意味のように見えますが、下記2つの場合において意味があります。
- 続けて
&allow-other-keys
を指定した場合 defmethod
かdefgeneric
でエラー回避のため
それぞれ説明します。
続けて&allow-other-keys
を指定した場合
&allow-other-keys
の場合は簡単に説明できます。
例えば下記の通り。
(defun aaa (value &key &allow-other-keys) ...)
このようにすることで、関数aaa
の引数にkey-value
の形を要求させることができます。
関数aaa
を呼び出すことを考えましょう。
例えば、下記の場合は問題ないです。
(aaa 100 :aaa 200 'bbb 300)
しかし、key-value
の形になっていない場合はエラーです。
(aaa 100 :aaa 200 'bbb) →★エラー、valueが足りない (aaa 100 :aaa 200 300 400) →★エラーの可能性あり、keyは本来symbolじゃないとダメ
関数aaa
では、引数を指定した所でただ内容を切り捨てています。
そうではなく引数&key
に加えて、&rest
だったり
マクロなら&whole
や&body
と組み合わせるなら、
もっとちゃんとした使い方ができると思います。
(defun aaa (value &rest args &key &allow-other-keys) ...)
この例では、key-value
の形を要求していることに加えて、
その内容を&rest
にてargs
に格納しています。
defmethod
かdefgeneric
でエラー回避のため
ではdefmethod
かdefgeneric
の方はどうでしょうか。
defgeneric
とdefmethod
には、lambda-list
を設定するときに、
守らなければいけない条件がいくつかあります。
そのうちの一部を下記に示します。
defgeneric
に&rest
か&key
があるなら、defmethod
に&rest
か&key
が必要。defmethod
に&rest
か&key
があるなら、defgeneric
に&rest
か&key
が必要。
では下記の例を見てみましょう。
(defgeneric aaa (value &rest args))
defgeneric
の引数には&rest
が含まれているので、
defmethod
では&rest
か&key
が必要になります。
続けて次の例を見ていきます。
(defmethod aaa (value &key hello) ...)
上記のmethod
では&key
があるので問題なしです。
次はどうでしょうか。
(defmethod aaa (value) ...)
上記はエラーです。
defgeneric
に&rest
があるのに、method
には&rest
も&key
もありません。
では次の例はどうでしょうか。
(defmethod aaa (value &key) ...)
面白いことに、&key
があるから問題ないとみなされます。
(defmethod aaa (value) ;; ★エラー ...) (defmethod aaa (value &key) ;; ★問題なし ...)
上記2例は、受け取ることができる引数は全く同じであるにもかかわらず、
下の方だけが合法で、lambda-list
のエラーチェックを回避できるのです。