ore*_*uro 6 lisp common-lisp variadic-functions keyword-argument
我希望同时使用&rest
,并&key
在同一时间。但是,下面的尝试代码:
(defun test (&rest args &key (name "who")) nil)
(test 1 2 3 4 5 :name "hoge")
Run Code Online (Sandbox Code Playgroud)
导致错误:
*** - 测试: (1 2 3 4 5 :NAME "hoge") 中的关键字参数应该成对出现
当我只给出关键字参数时(test :name "hoge")
,它就起作用了。是否可以同时使用 &rest 和 &key?
的组合&key
和
&rest
实际上是非常
常见的Common Lisp中,但几乎总是一起
&allow-other-keys
。
例如,假设您想为其定义一个包装器
write
但不想显式列出它所采用的所有关键字参数:
(defun my-write (object &rest args &key stream &allow-other-keys)
(write "my wrapper" :stream stream)
(apply #'write object args))
Run Code Online (Sandbox Code Playgroud)
你会发现许多地方,这种
&rest
/ &key
/&allow-other-keys
使用模式的任何地方CLOS实际
执行。
在 Common Lisp 的函数定义中,将 rest 参数与关键字参数混合在一起通常不是一个好主意。如果这样做,您可能应该考虑重写函数定义,因为它可能会导致一些意外行为。如果 &rest 和 &key 都出现在参数列表中,那么这两种情况都会发生——所有剩余的值,包括关键字本身,都被收集到一个绑定到 &rest 参数的列表中,并且适当的值也绑定到 &key参数。因此(名称“who”)关键字参数默认绑定到您的其余参数列表。如果您尝试输入参数 (1 2 3 4 5),您将收到错误消息,因为它们未绑定到您的参数(名称“who”)。下面是一个例子:
(defun test (&rest args &key (name "who"))
(list args name))
Run Code Online (Sandbox Code Playgroud)
在这里,我们有您的函数定义。如果我们尝试调用返回参数列表的函数,我们将在这里看到 &rest 参数绑定到它们的 &key 参数:
CL-USER> (test :name "Davis")
((:NAME "Davis") "Davis")
Run Code Online (Sandbox Code Playgroud)
通过在同一参数列表中混合 &rest 参数和关键字参数,您将无法输入任何与关键字参数不匹配的其余参数,这就是您在此处进入 breakloop 的原因。
现在,如果要创建宏,技术上可以在定义中使用多个参数列表,并在一个列表中添加关键字参数,在另一个列表中添加 &rest(或 &body)参数:
(defmacro hack-test ((&key (name "who")) &body body)
`(list ,name ,@body))
CL-USER> (hack-test (:name "Ricky")
(+ 2 3))
("Ricky" 5)
CL-USER> (hack-test ()
(+ 2 4)
(+ 4 5)
(+ 9 9))
("who" 6 9 18)
CL-USER>
Run Code Online (Sandbox Code Playgroud)