declare 形式 ¶declare 是一个特殊宏,可用于为函数或宏添加元属性:例如,将其标记为废弃,或在 Emacs Lisp 模式中为其形式指定特殊的 TAB 缩进规则。
该宏会忽略参数并求值为 nil,它没有运行时效果。但是,当 declare 形式出现在 defun、defsubst 函数定义(see 定义函数)或 defmacro 宏定义(see 定义宏)的 declare 参数中时,它会将 specs 指定的属性附加到该函数或宏上。这项工作由 defun、defsubst 和 defmacro 专门完成。
specs 中的每个元素都应具有形式 (property args…),且不应该被引用。它们具有如下作用:
(advertised-calling-convention signature when) ¶其效果等价于调用 set-advertised-calling-convention(see 声明函数为废弃状态)。signature 指定调用该函数或宏的正确参数列表,when 应为一个字符串,指明旧参数列表从何时起被标记为废弃。
(debug edebug-form-spec)仅对宏有效。使用 Edebug 单步执行宏时,将使用 edebug-form-spec。See 宏调用插桩。
(doc-string n)用于定义那些自身会用来定义函数、宏、变量等实体的函数或宏。它指明第 n 个参数(如果存在)应被视为文档字符串。
(indent indent-spec)按照 indent-spec 对该函数或宏的调用进行缩进。通常用于宏,但也适用于函数。See 宏的缩进。
(interactive-only value)将函数的 interactive-only 属性设为 value。See The interactive-only property。
(obsolete current-name when) ¶将函数或宏标记为废弃,效果类似于调用 make-obsolete(see 声明函数为废弃状态)。current-name 可以是:
一个符号(此时警告信息会提示改用该符号);
一个字符串(直接作为警告信息);
或 nil(此时警告信息不提供额外说明)。
when 应为字符串,指明该函数或宏首次被标记为废弃的时间。
(compiler-macro expander) ¶仅可用于函数,告知编译器将 expander 用作优化函数。当遇到形如 (function args…) 的函数调用时,宏展开器会以该表达式以及 args… 为参数调用 expander。expander 可以返回一个新表达式以替换原函数调用,也可以直接返回原表达式,表示不修改该函数调用。
当 expander 是 lambda 形式时,它应当只带一个参数(即形如 (lambda (arg) body)),因为该函数的形式参数会由系统自动添加到 lambda 的参数列表中。
(gv-expander expander)声明 expander 为用于将该宏(或函数)的调用作为广义变量处理的函数,作用与 gv-define-expander 类似。expander 可以是一个符号,也可以是形如 (lambda (arg) body) 的形式,此时该函数还能访问宏(或函数)的参数。
(gv-setter setter)声明 setter 为用于将该宏(或函数)的调用作为广义变量处理的设置函数。若 setter 是符号,则会被传给 gv-define-simple-setter;它也可以是形如 (lambda (arg) body) 的形式,此时该函数能访问宏(或函数)的参数,并会被传给 gv-define-setter。
(completion completion-predicate)声明 completion-predicate 为一个判断函数,用于决定在 M-x 补全时,是否将某个函数的符号加入函数列表。该判断函数仅当 read-extended-command-predicate 被自定义为 command-completion-default-include-p 时才会被调用;默认情况下 read-extended-command-predicate 的值为 nil(see execute-extended-command)。判断函数 completion-predicate 会被传入两个参数:函数的符号与当前缓冲区。
(modes modes)指明该命令仅适用于指定的 modes(主模式)。See Specifying Modes For Commands。
(interactive-args arg ...)指定需要为 repeat-command 保存的参数。每个 arg 的形式为 argument-name form。
(pure val)若 val 为非 nil,则该函数为 纯函数(pure)(see 什么是函数?)。这与函数符号的 pure 属性作用相同(see 标准符号属性)。
(side-effect-free val)若 val 为非 nil,则该函数无副作用,因此字节编译器可以忽略那些不使用返回值的调用。这与函数符号的 side-effect-free 属性作用相同,see 标准符号属性。
(important-return-value val)若 val 为非 nil,字节编译器会对不使用该函数返回值的调用发出警告。这与函数符号的 important-return-value 属性作用相同,see 标准符号属性。
(speed n)指定该函数在本地编译时生效的 native-comp-speed 值(see 本地编译变量)。这允许在函数级别控制为该函数生成本地代码时使用的优化级别。特别地,如果 n 为 −1,该函数的本地编译将只生成字节码,而非本地机器码。
(safety n)指定该函数生效的 compilation-safety 值。这允许在函数级别控制为该函数生成代码时使用的安全级别(see 本地编译变量)。
(ftype type &optional function) ¶将 type 声明为该函数的类型。该类型会被 describe-function 用于文档展示,并被本地编译器(see Lisp 本地代码编译)用于代码优化与类型推导。错误的类型声明可能导致本地编译后的代码崩溃(见下文)。带有类型声明的函数在 C-h C-f 中会显示为拥有 声明类型(declared type),与之相对,无声明的函数则显示 推导类型(inferred type)。
type 是一个 类型说明符(type specifier)(see 类型说明符),形式为:(function (arg-1-type … arg-n-type) RETURN-TYPE)。参数类型中可以穿插 &optional 和 &rest,以反映函数的调用规范(see 参数列表的特性)。
如果存在 function,它应当是正在定义的函数的名称。
下面是在 declare 中使用 ftype 定义函数 positive-p 的示例:该函数接受一个 number 类型的参数,并返回一个 boolean 类型的值。
(defun positive-p (x)
(declare (ftype (function (number) boolean)))
(when (> x 0)
t))
类似地,下面定义了一个函数 cons-or-number:它的第一个参数类型为 cons 或 number,第二个是 string 类型的可选参数,并返回符号 is-cons 或 is-number 中的一个:
(defun cons-or-number (x &optional err-msg)
(declare (ftype (function ((or cons number) &optional string)
(member is-cons is-number))))
(if (consp x)
'is-cons
(if (numberp x)
'is-number
(error (or err-msg "Unexpected input")))))
有关更多类型的说明,参见 Lisp 数据类型。
使用错误的类型声明函数会导致未定义行为。如果这样的函数在本地编译时将 compilation-safety 设置为 0(see compilation-safety),则可能在加载编译后的代码时出现执行错误,甚至导致 Emacs 崩溃。对已声明类型的函数进行重定义或 advice 增强时,必须保留原有的签名,以避免此类问题。
no-font-lock-keyword仅对宏有效。带有该声明的宏在字体高亮(see Font Lock Mode)下会像普通函数一样高亮,而不会被特殊标记为宏。