6.3 参数列表 (Parameter Lists)
2.1 节我们演示过,有了前序表达式, +
可以接受任何数量的参数。从那时开始,我们看过许多接受不定数量参数的函数。要写出这样的函数,我们需要使用一个叫做剩余( rest )参数的东西。
如果我们在函数的形参列表里的最后一个变量前,插入 &rest
符号,那么当这个函数被调用时,这个变量会被设成一个带有剩余参数的列表。现在我们可以明白 funcall
是如何根据 apply
写成的。它或许可以定义成:
(defun our-funcall (fn &rest args)
(apply fn args))
我们也看过操作符中,有的参数可以被忽略,并可以缺省设成特定的值。这样的参数称为选择性参数(optional parameters)。(相比之下,普通的参数有时称为必要参数「required parameters」) 如果符号 &optional
出现在一个函数的形参列表时,
(defun philosoph (thing &optional property)
(list thing 'is property))
那么在 &optional
之后的参数都是选择性的,缺省为 nil
:
> (philosoph 'death)
(DEATH IS NIL)
我们可以明确指定缺省值,通过将缺省值附在列表里给入。这版的 philosoph
(defun philosoph (thing &optional (property 'fun))
(list thing 'is property))
有着更鼓舞人心的缺省值:
> (philosoph 'death)
(DEATH IS FUN)
选择性参数的缺省值可以不是常量。可以是任何的 Lisp 表达式。若这个表达式不是常量,它会在每次需要用到缺省值时被重新求值。
一个关键字参数(keyword parameter)是一种更灵活的选择性参数。如果你把符号 &key
放在一个形参列表,那在 &key
之后的形参都是选择性的。此外,当函数被调用时,这些参数会被识别出来,参数的位置在哪不重要,而是用符号标签(译注: :
)识别出来:
> (defun keylist (a &key x y z)
(list a x y z))
KEYLIST
> (keylist 1 :y 2)
(1 NIL 2 NIL)
> (keylist 1 :y 3 :x 2)
(1 2 3 NIL)
和普通的选择性参数一样,关键字参数缺省值为 nil
,但可以在形参列表中明确地指定缺省值。
关键字与其相关的参数可以被剩余参数收集起来,并传递给其他期望收到这些参数的函数。举例来说,我们可以这样定义 adjoin
:
(defun our-adjoin (obj lst &rest args)
(if (apply #'member obj lst args)
lst
(cons obj lst)))
由于 adjoin
与 member
接受一样的关键字,我们可以用剩余参数收集它们,再传给 member
函数。
5.2 节介绍过 destructuring-bind
宏。在通常情况下,每个模式(pattern)中作为第一个参数的子树,可以与函数的参数列表一样复杂:
(destructuring-bind ((&key w x) &rest y) '((:w 3) a)
(list w x y))
(3 NIL (A))