我今天尝试编写一个 elisp 函数,除了函数返回 nil 时不断抛出的错误之外,一切都运行良好。这是函数:(请原谅格式,我还不确定如何缩进它。
(defun byte-is-readable (byte)
"Determine whether BYTE is readable or not.
Returns t or nil."
(if (and (<= byte 126) (>= byte 32)) t nil))
;; Read the 100 bytes of a file
;; If 10 in a row are not 'readable', it is safe to assume the file is a binary
(defun is-file-binary (file)
"Determine whether FILE is a binary file.
Returns t or nil."
(let* ((i 1)
(c 0)
(size (nth 7 (file-attributes file)))
(lim (if (< size 100) size 100)))
(while (< i lim)
(let ((char (with-temp-buffer
(insert-file-contents file)
(buffer-substring i (+ i 1)))))
(if (not (byte-is-readable (aref char 0)))
(setq c (+ c 1))
(setq c 0))
(if (= c 10) (return t)))
(setq i (+ i 1))))
nil)
像这样调用它:返回 true 时(message "%s" (if (is-file-binary "/path/to/some/file") "true" "false")
工作文件,但在返回 nil 时抛出"if:没有捕获标签:--cl-block-nil--, t"。我猜这是因为 nil 没有正确评估或其他什么。
我该如何解决?
该错误来自您在代码中使用return
的事实。这是一个宏,仅在其他一些宏的上下文中具有有意义的扩展cl
例如 loop
.
我鼓励您使用loop
而不是while
,因为它允许隐藏无趣的实现细节,例如计数器、throw
- catch
机制等。但是,如果您出于任何原因想要使用while
那么从循环中断while
方法是使用:
(catch 'label (while <condition> ... (throw 'label <result>)))
使用 loop
的代码版本。
(defun byte-readable-p (byte)
"Determine whether BYTE is readable or not.
Returns t or nil."
(cl-case byte
((?n ?r ?t) t)
(otherwise (and (<= byte 126) (>= byte 32)))))
(defun file-binary-p (file)
"Determine whether FILE is a binary file.
Returns t or nil."
(with-temp-buffer
(insert-file-contents file)
(cl-loop for c across
(buffer-substring-no-properties
1 (min 100 (buffer-size)))
thereis (not (byte-readable-p c)))))
(file-binary-p (expand-file-name "~/.emacs"))
nil
(file-binary-p (expand-file-name "~/.emacs.d/elpa/w3m-20131021.2047/w3m.elc"))
t
或者,更短的版本,使用高阶函数:
(defun file-binary-p (file)
"Determine whether FILE is a binary file.
Returns t or nil."
(with-temp-buffer
(insert-file-contents file)
(cl-find-if-not 'byte-readable-p
(buffer-substring-no-properties
1 (min 100 (buffer-size))))))
请注意,传统上,在 Lisp 代码中,返回布尔值(通常称为"谓词")的函数使用方案命名:<word>p
或<word>-<word>-p
而不是is-<word>
。