所以我有一些我想要的东西,在try块中,向一些数据对象添加各种数据,然后在抛出异常的情况下,保存带有错误的记录和在异常之前检索的所有数据字段.在Java中,这很容易.即使你使用某种不可变类型的记录,你也可以这样做:
MyRecord record = new MyRecord();
try {
record = record.withA(dangerouslyGetA());
record = record.withB(dangerouslyGetB());
record = record.withC(dangerouslyGetC());
} catch (Exception ex) {
record = record.withError(ex);
}
save(record);
Run Code Online (Sandbox Code Playgroud)
因此,如果它在步骤C发生炸弹,那么它将保存A,B和错误的记录.
我无法在Clojure中找出任何直接的方法.如果你放了try一个,let那么你必须将记录的"更新"分配给每个新变量,因此它们不在catch表达式的范围内.即使它们是,你也不会知道使用哪一个.
我想我可以在每个表达式周围放置一个try/catch/let,但这比Java版本要多得多,并且需要在save任何地方复制语句.我的理解是,Clojure的简洁性和容易避免重复是很好的,所以有些东西让我觉得这是错误的方法.
当然这是一个相当普遍的需求,并有一个简单的惯用解决方案,对吧?
我认为包装每一个语句实际上是最惯用的解决方案.如果您不想写太多,可以构建一个宏来为您的单个步骤添加异常处理.
(defmacro with-error->
[error-fn value & forms]
(if-not (seq forms)
value
`(let [ef# ~error-fn
v# ~value]
(try
(with-error-> ef# (-> v# ~(first forms)) ~@(rest forms))
(catch Exception ex# (ef# v# ex#))))))
Run Code Online (Sandbox Code Playgroud)
如果调用块,它的行为类似->但会调用error-fn当前值(和异常)catch:
(with-error-> #(assoc % :error %2) {}
(assoc :x 0)
(assoc :y 1)
(assoc :z (throw (Exception. "oops.")))
(assoc :a :i-should-not-be-reached))
;; => {:error #<Exception java.lang.Exception: oops.>, :y 1, :x 0}
Run Code Online (Sandbox Code Playgroud)
当然,你总是可以用可变的状态来做,比如一个atom,但我不认为你应该用一点点的宏来实现同样的目标.
| 归档时间: |
|
| 查看次数: |
306 次 |
| 最近记录: |