Emacs Lisp:返回 nil 时"if: No catch for tag: --cl-block-nil--, t"



我今天尝试编写一个 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>

最新更新