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 函数,值得单独用一小节讲解。