13.2.3 参数列表的特性

我们这个简单的示例函数 (lambda (a b c) (+ a b c)) 指定了三个参数变量,因此调用时必须传入三个参数: 若尝试仅传入两个或四个参数,会触发 wrong-number-of-arguments 错误 (see 错误)。

编写支持省略特定参数的函数往往会带来便利。例如函数 substring 接受三个参数——一个字符串、起始索引和结束索引——但如果省略第三个参数, 其默认值会设为该字符串的 长度。此外,让某些函数支持接收数量不定的参数 也很实用,就像 list+ 函数那样。

若要指定函数调用时可省略的可选参数,只需在这些可选参数前加入关键字 &optional 即可。 若要接收零个或多个额外参数(形成参数列表),则在最后一个参数前加入关键字 &rest

因此,参数列表的完整语法格式如下:

(required-vars...
 [&optional [optional-vars...]]
 [&rest rest-var])

方括号表示 &optional&rest 子句及其后续的变量均为可选内容。

调用函数时,每个 required-vars 都需要对应一个实际参数。 零个或多个 optional-vars 可附带实际参数;除非 lambda 列表使用了 &rest, 否则不允许传入超出该范围的实际参数。若使用了 &rest,则可传入任意数量的额外实际参数。

若省略可选变量和剩余变量对应的实际参数,这些变量会默认取值为 nil。 函数无法区分「显式传入的 nil 参数」和「省略的参数」。 不过函数体可自行将 nil 视为其他有意义值的简写形式。 substring 函数正是如此:向其第三个参数传入 nil, 等价于使用所传入字符串的长度作为该参数值。

通用Lisp说明: 通用Lisp允许函数指定可选参数省略时使用的默认值; 而Emacs Lisp始终将 nil 作为默认值。Emacs Lisp不支持通过 supplied-p 变量判断参数是否被显式传入。

例如,形如下面这样的参数列表:

(a b &optional c d &rest e)

该参数列表会将 ab 绑定到前两个实际参数(这两个参数为必传项)。 若传入更多的一个或两个参数,则 cd 会分别绑定到这些参数; 前四个参数之后的所有参数会被收集为一个列表,e 则绑定到该列表。 因此:若仅传入两个参数,cde 的值均为 nil; 若传入两个或三个参数,de 的值为 nil; 若传入四个及以下参数,e 的值为 nil。 需注意:若恰好传入五个参数,且为 e 显式传入 nil 作为参数, 该 nil 参数会以包含一个元素的列表(即 (nil))形式传递给 e—— 这与为 e 传入任何其他单一值的处理方式一致。

必选参数不能出现在可选参数之后——这种写法在逻辑上毫无意义。 要理解为何必须遵循此规则,不妨假设示例中的 c 为可选参数、d 为必选参数: 若传入三个实际参数,第三个参数应绑定到哪个变量?是绑定给 c,还是 d? 两种解读都能找到理由。同理,在 &rest 参数之后也不能再出现任何参数 (无论是必选参数还是可选参数),这同样不符合逻辑。

以下是一些参数列表及合法调用的示例:

(funcall (lambda (n) (1+ n))        ; One required:
         1)                         ; requires exactly one argument.
     ⇒ 2
(funcall (lambda (n &optional n1)   ; One required and one optional:
           (if n1 (+ n n1) (1+ n))) ; 1 or 2 arguments.
         1 2)
     ⇒ 3
(funcall (lambda (n &rest ns)       ; One required and one rest:
           (+ n (apply '+ ns)))     ; 1 or more arguments.
         1 2 3 4 5)
     ⇒ 15

emacs

Emacs

org-mode

Orgmode

Donations

打赏

Copyright

© 2025 Jasper Hsu

Creative Commons

Creative Commons

Attribute

Attribute

Noncommercial

Noncommercial

Share Alike

Share Alike