3

我正在尝试做的事情:我想要simple-error另一个错误中的功能。我想要这个,原因如下:

  • 能够在 的单独子句中处理它handler-case

  • 避免一遍又一遍地指定消息字符串...

  • 在发生错误时调用调试器。

我有点困惑,默认情况下这不会自然发生,从未对这个问题给予足够的关注,但这显然是它的功能......我能做的是发出错误信号,稍后我可以处理使用handler-caseor handler-bind,但这很糟糕,因为我并不总是记得函数是否抛出,以及当它抛出时,但我忘记处理它,函数只是提前返回,好像什么也没发生一样。但是如果我继续使用simple-error,那么我的代码开始看起来像:

...
(signal "Container ~S has no key ~S~&" :container foo :key bar)
...
(signal "Container ~S has no key ~S~&" :container foo :key baz)
...

等等,到处都是:/当然我可以专门使用一个变量来保存消息文本,也许还有一个宏可以使它更短,但这并没有真正的帮助,因为它只会隐藏实际的混乱而不是解决问题。

到目前为止我能做的:

(define-condition missing-key (condition)
  ((key :initarg :key
        :accessor key-of)
   (container :initarg :container
              :accessor container-of))
  (:documentation
   "An error rised when a KEY is not in the CONTAINER"
   :report
   #'(lambda (condition stream)
       (unless *print-escape*
         (format stream "~&Container ~S has no key ~S"
                 (container-of condition)
                 (key-of condition))))))

(handler-bind
    ((missing-key
      #'(lambda (condition)
          (invoke-debugger condition))))
  (signal 'missing-key :key 'foo :container 'bar))

然而,发生的事情是报告函数永远不会被调用......当错误发出信号时,它会打印一条通用消息Condition MISSING-KEY was signalled.

编辑:

感谢 sds 的回答,这就是我现在所拥有的:

(define-condition missing-key (error)
  ((key :initarg :key
        :accessor key-of)
   (container :initarg :container
              :accessor container-of))
  (:documentation
   "An error rised when a KEY is not in the CONTAINER")
  (:report
   (lambda (condition stream)
     (format stream "Container ~S has no key ~S"
             (container-of condition)
             (key-of condition)))))

(defmacro signal-missing-key (container key)
  `(let ((*break-on-signals*
          (cond
            ((null *break-on-signals*) 'missing-key)
            ((consp *break-on-signals*)
             (list 'or 'missing-key (cdr *break-on-signals*)))
            (t (list 'or *break-on-signals* 'missing-key)))))
     (signal 'missing-key :key ,container :container ,key)))

我可能可以通过将更多参数传递给它来使其更通用signal,但这正是我最初想做的事情,所以,除非有更好的方法来做同样的事情,否则我可能会使用它。

4

3 回答 3

2

您的代码通过以下修改按预期工作:删除#'之前lambda,删除~&format错误报告会这样做等等),关闭:documentation子句并打开:report子句:

(define-condition missing-key (condition)
  ((key :initarg :key
        :accessor key-of)
   (container :initarg :container
              :accessor container-of))
  (:documentation
   "An error rised when a KEY is not in the CONTAINER")
  (:report
   (lambda (condition stream)
       (unless *print-escape*
         (format stream "Container ~S has no key ~S"
                 (container-of condition)
                 (key-of condition))))))
MISSING-KEY
(signal 'missing-key :key 'foo :container 'bar)
==> NIL
(handler-bind
    ((missing-key
      #'(lambda (condition)
          (invoke-debugger condition))))
  (signal 'missing-key :key 'foo :container 'bar))


*** - Container BAR has no key FOO
The following restarts are available:
ABORT          :R1      Abort main loop
Break 1 [46]> 

即,除了调用调试器signal之外什么都不打印。handler

于 2012-11-30T21:05:08.210 回答
2

如果您希望调用调试器,除非条件以其他方式处理,否则您可以使用error或与您自己的条件类型一起使用。cerror这也适用于不是simple-error.

如果您也想要这种行为signal,您可以将变量设置*break-on-signals*为相应的类型。例如,您可以将其设置为t以便为每个未处理的条件调用调试器。

于 2012-12-02T02:37:09.797 回答
1

使您的条件成为ERROR而不是的子类CONDITION。并非所有条件都是需要通过调试器进行干预的错误,并且条件类层次结构旨在区分它们。

于 2012-11-30T19:41:11.037 回答