你如何解决这个问题?
假设我想编写一个执行以下操作的函数:如果用户安装了库X,则使用函数X函数,否则 - 跳过?
我尝试了什么:
(when (symbol-function 'X-function)
(X-function))
我收到了有关此代码的警告 - 那么正确的方法是什么?
答案 0 :(得分:4)
这个怎么样:
(when (fboundp 'X-function)
(X-function))
http://www.gnu.org/software/emacs/manual/html_node/elisp/Function-Cells.html上的文档说明了符号功能
如果符号的函数单元格为空,则发出无效函数错误信号。
我猜这就是你所看到的。另一方面,fboundp只返回t或nil,具体取决于函数是否存在。
答案 1 :(得分:4)
抑制此编译器警告的方法是:
(declare-function X-function "ext:X-library.el")
(when (fboundp 'X-function)
(X-function))
这里X-library是库存在时定义X函数的库的名称。然后字节编译器将执行以下操作:
因此,如果没有X库,它就不会抱怨,但如果有一个并且它没有定义函数,那么它就会。这意味着如果库的更新版本不包含X-function,那么您将知道何时尝试重新编译代码。
如果你查看declare-function的文档,你会发现它也可以检查函数的参数列表。
顺便说一下,如果您收到有关未声明变量的类似警告,可以使用以下方法禁止这些:
(defvar X-variable)
但是,即使您知道库将其设置为什么值,也不要设置变量,因为这可能会在以后的版本中发生变化。
这为您提供了一个版本的程序,无论X库是否存在,该程序都有效。您可能更喜欢有两个版本,一个用于存在X库,另一个用于何时不存在。这可以通过宏来完成:
(defmacro run? (function &rest args)
"Expand to function call if function exists."
(when (fboundp `,function)
`(,function ,@args)))
现在而不是像:
之类的电话(X-function a1 a2 a3)
你写道:
(run? X-function a1 a2 a3)
如果使用X库进行编译,则会扩展为对X-function的调用。如果库不存在则会扩展为空。在任何情况下,您都不需要声明函数。这给出了两个不同的版本,但它应该更有效,因为关于库是否存在的决定是在编译时而不是运行时进行的。
一个小警告。如果您选择第二个解决方案,则必须在X库环境中或在其外部编译整个程序。如果您尝试在程序中途加载库,那么在解释时,它将按照您在加载前后不同扩展的宏的方式工作。但是在编译的程序中,宏只扩展一次。该库的测试测试是在代码中进行扩展而不是在扩展中,因此宏在加载之前和之后将不会起作用。
答案 2 :(得分:0)
另一种情况是,当您可以获得无法找到函数的警告时,是以编程方式定义函数并使用 fset 进行设置。以下示例说明了这一点以及如何处理它:
(eval-and-compile
(fset 'my-function1 (lambda () nil)))
(my-function1)
(fset 'my-function2 (lambda () nil))
(my-function2)
(my-function3)
(eval-and-compile
(fset 'my-function3 (lambda () nil)))
如果你编译它,你会收到警告:
Warning: the function `my-function2' is not known to be defined.
和
Warning: the function `my-function3' might not be defined at runtime.
如果您在同一个Emacs会话中第二次重新编译代码,第二个警告消失了,但第一个没有。
这里发生的是:当编译器看到 eval-and-compile 时,它首先评估当前Emacs会话中的主体,然后编译它。在评估了代码之后,Emacs了解了以编程方式定义的函数。
请注意, eval-and-compile ,如 eval-with-compile ,对于Emacs解释器看起来像 progn 。