13.15 declare 形式

declare 是一个特殊宏,可用于为函数或宏添加元属性:例如,将其标记为废弃,或在 Emacs Lisp 模式中为其形式指定特殊的 TAB 缩进规则。

Macro: declare specs…

该宏会忽略参数并求值为 nil,它没有运行时效果。但是,当 declare 形式出现在 defundefsubst 函数定义(see 定义函数)或 defmacro 宏定义(see 定义宏)的 declare 参数中时,它会将 specs 指定的属性附加到该函数或宏上。这项工作由 defundefsubstdefmacro 专门完成。

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… 为参数调用 expanderexpander 可以返回一个新表达式以替换原函数调用,也可以直接返回原表达式,表示不修改该函数调用。

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:它的第一个参数类型为 consnumber,第二个是 string 类型的可选参数,并返回符号 is-consis-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)下会像普通函数一样高亮,而不会被特殊标记为宏。


emacs

Emacs

org-mode

Orgmode

Donations

打赏

Copyright

© 2025 Jasper Hsu

Creative Commons

Creative Commons

Attribute

Attribute

Noncommercial

Noncommercial

Share Alike

Share Alike