计算 defun 的长度

使用 while 循环的设计很常规。函数接收的参数是文件列表。如前所述(see while 循环与列表), 你可以编写 while 循环,使其在列表包含元素时执行循环体,列表为空时退出循环。 要使该设计生效,循环体必须包含每次执行时缩短列表的表达式,最终使列表为空。 常用方法是每次执行循环体时,将列表值设为其 CDR

模板如下:

(while test-whether-list-is-empty
  body...
  set-list-to-cdr-of-list)

同时,我们记得 while 循环返回 nil(条件测试的求值结果),而非循环体内 任何求值的结果。(循环体内的求值依靠副作用完成。)但设置长度列表的表达式是循环体的一部分 — 而这正是我们希望函数整体返回的值。为此,我们将 while 循环包裹在 let 表达式内, 并使 let 表达式的最后一个元素为长度列表的值。(See Loop Example with an Incrementing Counter。)

基于这些考虑,我们直接得到函数本身:

;;; Use while loop.
(defun lengths-list-many-files (list-of-files)
  "Return list of lengths of defuns in LIST-OF-FILES."
  (let (lengths-list)

;;; true-or-false-test
    (while list-of-files
      (setq lengths-list
            (append
             lengths-list

;;; Generate a lengths’ list.
             (lengths-list-file
              (expand-file-name (car list-of-files)))))

;;; Make files’ list shorter.
      (setq list-of-files (cdr list-of-files)))

;;; Return final value of lengths’ list.
    lengths-list))

expand-file-name 是内置函数,将文件名转换为绝对长路径形式。 该函数使用调用时所在目录的名称。

因此,如果 Emacs 正在访问 /usr/local/share/emacs/22.1.1/lisp/emacs-lisp/ 目录, 对 debug.el 调用 expand-file-name

debug.el

会变为

/usr/local/share/emacs/22.1.1/lisp/emacs-lisp/debug.el

该函数定义中另一个新元素是尚未学习的 append 函数,值得单独用一小节讲解。