Common Lisp Condition

Table of Contents

Condition System 是 Common Lisp 中的异常处理机制。

1. define-condition

自定义一个状态(condition):

(define-condition test-error
    (error)
  ((text :initarg :text :reader text)))

2. error,触发一个condition

  • 参数为一个实例化的 condition
  • 或者指定 condition 名字

    (error (make-instance 'test-error))
    (error 'test-error :text "hehe")
    
[1]> (error "this is a error")

*** - this is a error
The following restarts are available:
ABORT          :R1      Abort main loop

3. handler-case

捕获 condition:

[5]> (define-condition foo() () (:report (lambda (condition stream) (princ "xxxx" stream))))
FOO
[6]> (defun bad-function () (error 'foo))
BAD-FUNCTION
[7]> (handler-case (bad-function) (foo () "error"))
"error"

4. restart

restart-case 提供重启的选项

handler-bind:

  • 可以捕获 restart
  • invoke-restart

5. unwind-protect

定义如下:

(unwind-protect protected &body cleanup)

可以为表达式提供一个“清理函数”,保证无论发生什么异常都会去执行。如:

(defun hello ()
  (unwind-protect
       (error "hello")
    ;; 一定在最后会被执行
    (print "exit")))

Common Lisp 中常见的 with- 开头的宏基本上都是封装了 unwind-protect 的,比如我们展开 with-open-file 看看:

(macroexpand '(with-open-file (f "/etc/passwd")))
;; 展开如下:
(LET ((F (OPEN "/etc/passwd")) (#:G930 T))
  (UNWIND-PROTECT (MULTIPLE-VALUE-PROG1 (PROGN) (SETQ #:G930 NIL))
    (WHEN F (CLOSE F :ABORT #:G930))))
T

6. 屏蔽异常处理信息

Common Lisp 有一个全局变量 *debugger-hook*,可以为它设置调试信息处理函数。

当执行以下代码时,会被异常处理中断:

(aref "1" 1)

现在,为 *debugger-hook* 设置一个函数来处理异常,让它只打印简单的异常信息:

(setf *debugger-hook*
      (lambda (c h)
        (declare (ignore h))
        (print c)
        (abort)))