gpt4 book ai didi

clojure - 如何在 Clojure 中的 try/catch block 中保留状态更新

转载 作者:行者123 更新时间:2023-12-02 12:38:00 24 4
gpt4 key购买 nike

所以我想要在 try block 内将各种数据添加到某个数据对象,然后在引发异常的情况下,保存包含错误的记录以及异常之前检索到的所有数据字段。在 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);

因此,如果它在步骤 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#))))))

其行为类似于 ->,但如果调用 catch block ,则会对当前值(和异常)调用 error-fn :

(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}

当然,您始终可以使用可变状态来做到这一点,例如一个atom,但我认为如果你可以通过一点宏功能实现相同的目的,你就不需要这样做。

关于clojure - 如何在 Clojure 中的 try/catch block 中保留状态更新,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20254187/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com