请考虑以下代码:
(define-condition some-condition (error) nil)
(defmethod print-object ((obj some-condition) stream)
(format stream "HELLO THERE"))
(defmacro error-report-test-aux (fn-to-cause-error error-type-to-catch fn-to-handle-error expected-message)
`(let ((result-message
(handler-case (funcall ,fn-to-cause-error)
(,error-type-to-catch (e) (funcall ,fn-to-handle-error e)))))
(assert (string= result-message
,expected-message))
t))
我可以像这样使用它:
(error-report-test-aux (lambda () (error 'some-condition))
some-condition
#'princ-to-string
"HELLO THERE")
但我想让error-report-test-aux
成为一个函数而不是宏,这样我就可以在变量中传递一种条件。
简单地写defun
而不是defmacro
并删除反引号和逗号不起作用,因为handler-case
是宏而且它不评估error-type-to-catch
。
我的问题是:是否有类似handler-case
的内容会评估它的参数(特别是条件类型参数)?
答案 0 :(得分:5)
是和否: - )
没有标准函数可以执行您想要的操作,因为捕获错误需要建立绑定,而且通常需要绑定常量符号(如let
/let*
中),因为它更容易优化
你可能考虑使用handler-bind
创建一个“通用”处理程序,然后拒绝处理“不感兴趣”的条件(正如@jkiiski在评论中所建议的那样),但我不确定是否符合您的确切要求(未经测试!):
(defun error-report-test-aux (fn-to-cause-error error-type-to-catch expected-message)
(catch 'trap
(handler-bind ((error
(lambda (condition)
(when (typep condition error-type-to-catch)
(throw 'trap (string= (princ-to-string condition)
expected-message))))))
(funcall fn-to-cause-error))))
IF 您的实现通过绑定内部全局变量来实现handler-case
/ handler-bind
,您可以使用progv
绑定它自己,然后将error-report-test-aux
作为一个函数实现。
这可能不是最好的主意(您的代码将与特定实现结合)。
您可以使用some-condition
命名CLOS类并使用泛型函数而不是宏的事实。