11.7.2 catchthrow 的示例

使用 catchthrow 的一种场景是退出双层嵌套循环。(在大多数编程语言中,这类需求会通过 goto 实现。)以下示例中,我们会计算当 ij 从 0 遍历到 9 时 (foo i j) 的值:

(defun search-foo ()
  (catch 'loop
    (let ((i 0))
      (while (< i 10)
        (let ((j 0))
          (while (< j 10)
            (if (foo i j)
                (throw 'loop (list i j)))
            (setq j (1+ j))))
        (setq i (1+ i))))))

foo 某次返回值为非 nil,则会立即终止执行,并返回一个包含 ij 的列表。若 foo 始终返回 nil,则 catch 会正常返回,其返回值为 nil—— 因为这正是 while 结构的执行结果。

以下是两个稍有差异的进阶示例,展示了同时存在两个返回点的场景。首先是两个返回点使用相同标记 hack 的情况:

(defun catch2 (tag)
  (catch tag
    (throw 'hack 'yes)))
⇒ catch2

(catch 'hack
  (print (catch2 'hack))
  'no)
⊣ yes
⇒ no

由于两个返回点的标记均与该 throw 匹配,因此 throw 会跳转到内层的那个返回点 —— 也就是在 catch2 中建立的返回点。因此,catch2 会正常返回,返回值为 yes,且该值会被打印输出。最后,外层 catch 代码体中的第二个形式(即 'no)会被求值,并作为外层 catch 的返回值。

接下来我们修改传给 catch2 的参数:

(catch 'hack
  (print (catch2 'quux))
  'no)
⇒ yes

我们仍然有两个返回点,但这一次只有外层返回点的标记是 hack;内层返回点的标记改为了 quux。因此,throw 会让外层的 catch 直接返回 yes。函数 print 不会被调用,代码体 'no 也不会被求值。


emacs

Emacs

org-mode

Orgmode

Donations

打赏

Copyright

© 2025 Jasper Hsu

Creative Commons

Creative Commons

Attribute

Attribute

Noncommercial

Noncommercial

Share Alike

Share Alike