6.3 参数列表 (Parameter Lists)

2.1 节我们演示过,有了前序表达式, + 可以接受任何数量的参数。从那时开始,我们看过许多接受不定数量参数的函数。要写出这样的函数,我们需要使用一个叫做剩余( rest )参数的东西。

如果我们在函数的形参列表里的最后一个变量前,插入 &rest 符号,那么当这个函数被调用时,这个变量会被设成一个带有剩余参数的列表。现在我们可以明白 funcall 是如何根据 apply 写成的。它或许可以定义成:

  1. (defun our-funcall (fn &rest args)
  2. (apply fn args))

我们也看过操作符中,有的参数可以被忽略,并可以缺省设成特定的值。这样的参数称为选择性参数(optional parameters)。(相比之下,普通的参数有时称为必要参数「required parameters」) 如果符号 &optional 出现在一个函数的形参列表时,

  1. (defun philosoph (thing &optional property)
  2. (list thing 'is property))

那么在 &optional 之后的参数都是选择性的,缺省为 nil :

  1. > (philosoph 'death)
  2. (DEATH IS NIL)

我们可以明确指定缺省值,通过将缺省值附在列表里给入。这版的 philosoph

  1. (defun philosoph (thing &optional (property 'fun))
  2. (list thing 'is property))

有着更鼓舞人心的缺省值:

  1. > (philosoph 'death)
  2. (DEATH IS FUN)

选择性参数的缺省值可以不是常量。可以是任何的 Lisp 表达式。若这个表达式不是常量,它会在每次需要用到缺省值时被重新求值。

一个关键字参数(keyword parameter)是一种更灵活的选择性参数。如果你把符号 &key 放在一个形参列表,那在 &key 之后的形参都是选择性的。此外,当函数被调用时,这些参数会被识别出来,参数的位置在哪不重要,而是用符号标签(译注: : )识别出来:

  1. > (defun keylist (a &key x y z)
  2. (list a x y z))
  3. KEYLIST
  4. > (keylist 1 :y 2)
  5. (1 NIL 2 NIL)
  6. > (keylist 1 :y 3 :x 2)
  7. (1 2 3 NIL)

和普通的选择性参数一样,关键字参数缺省值为 nil ,但可以在形参列表中明确地指定缺省值。

关键字与其相关的参数可以被剩余参数收集起来,并传递给其他期望收到这些参数的函数。举例来说,我们可以这样定义 adjoin

  1. (defun our-adjoin (obj lst &rest args)
  2. (if (apply #'member obj lst args)
  3. lst
  4. (cons obj lst)))

由于 adjoinmember 接受一样的关键字,我们可以用剩余参数收集它们,再传给 member 函数。

5.2 节介绍过 destructuring-bind 宏。在通常情况下,每个模式(pattern)中作为第一个参数的子树,可以与函数的参数列表一样复杂:

  1. (destructuring-bind ((&key w x) &rest y) '((:w 3) a)
  2. (list w x y))
  3. (3 NIL (A))