10.2.4 符号函数间接引用

如果列表的第一个元素是一个符号,那么在求值时会检查该符号的函数单元格,并使用其中的内容替代原来的符号。如果该内容仍然是另一个符号,这个被称为 符号函数间接引用(symbol function indirection) 的过程会被重复执行,直到得到一个非符号对象为止。See 函数命名,了解更多关于符号函数间接引用的信息。 我们最终会得到一个非符号对象,它应当是一个函数或其他合适的对象。

更精确地说,此时我们应该得到以下对象之一:Lisp 函数(lambda 表达式)、字节码函数、原语函数、Lisp 宏、特殊形式,或是自动加载对象。这些类型将在后续章节中分别介绍。如果该对象不属于上述任何一种类型,Emacs 将会抛出一个 invalid-function(无效函数)错误。

下面的例子演示了符号间接引用的过程。我们使用 fset 来设置符号的函数单元格,并用 symbol-function 获取函数单元格的内容(see 访问函数单元内容)。具体来说:我们将符号 car 存入符号 first 的函数单元格,再将符号 first 存入符号 erste 的函数单元格。

;; Build this function cell linkage:
;;   -------------       -----        -------        -------
;;  | #<subr car> | <-- | car |  <-- | first |  <-- | erste |
;;   -------------       -----        -------        -------
(symbol-function 'car)
     ⇒ #<subr car>
(fset 'first 'car)
     ⇒ car
(fset 'erste 'first)
     ⇒ first
(erste '(1 2 3))   ; Call the function referenced by erste.
     ⇒ 1

与之相反,下面这个示例在调用函数时不会发生任何符号函数间接引用,因为列表的第一个元素是一个匿名 Lisp 函数,而不是符号。

((lambda (arg) (erste arg))
 '(1 2 3))
     ⇒ 1

执行函数本身会对其函数体进行求值;在调用 erste 时,这一过程仍然会触发符号函数间接引用。

这种写法很少使用,现已被废弃。你应当改用下面的写法:

(funcall (lambda (arg) (erste arg))
         '(1 2 3))

or just

(let ((arg '(1 2 3))) (erste arg))

内置函数 indirect-function 提供了一种便捷的方式,可显式地执行符号函数间接引用操作。

Function: indirect-function function

该函数返回 function 作为函数的实际指向(语义)。若 function 是一个符号,则函数会先查找该符号的函数定义,并以该定义值为起点重新执行上述查找过程;若 function 不是符号,则直接返回 function 本身。

如果最终查找的符号未绑定函数(unbound),该函数会返回 nil

该函数还有第二个可选参数,但此参数已被废弃(obsolete),且无任何实际作用。

以下是如何用 Lisp 语言自定义实现 indirect-function 的示例:

(defun indirect-function (function)
  (if (and function
           (symbolp function))
      (indirect-function (symbol-function function))
    function))

emacs

Emacs

org-mode

Orgmode

Donations

打赏

Copyright

© 2025 Jasper Hsu

Creative Commons

Creative Commons

Attribute

Attribute

Noncommercial

Noncommercial

Share Alike

Share Alike