我试图在放弃异常之前多次执行一个函数.但是在Clojure中从catch块中重现是无效的.怎么能实现这一目标?
(loop [tries 10]
(try
(might-throw-exception)
(catch Exception e
(when (pos? tries) (recur (dec tries))))))
java.lang.UnsupportedOperationException: Cannot recur from catch/finally
Run Code Online (Sandbox Code Playgroud)
我能找到的最好的是以下笨拙的解决方案(包装在func中并调用它)
(defn do-it []
(try
(might-throw-exception)
(catch Exception e nil)))
(loop [times 10]
(when (and (nil? (do-it)) (pos? times))
(recur (dec times))))
Run Code Online (Sandbox Code Playgroud)
kot*_*rak 44
宏正在呼唤......
这个怎么样:
(defn try-times*
"Executes thunk. If an exception is thrown, will retry. At most n retries
are done. If still some exception is thrown it is bubbled upwards in
the call chain."
[n thunk]
(loop [n n]
(if-let [result (try
[(thunk)]
(catch Exception e
(when (zero? n)
(throw e))))]
(result 0)
(recur (dec n)))))
(defmacro try-times
"Executes body. If an exception is thrown, will retry. At most n retries
are done. If still some exception is thrown it is bubbled upwards in
the call chain."
[n & body]
`(try-times* ~n (fn [] ~@body)))
Run Code Online (Sandbox Code Playgroud)
ama*_*loy 12
kotarak的想法是要走的路,但这个问题让我感到奇怪,所以我想提供一个与我喜欢的相同主题的riff,因为它不使用loop/recur:
(defn try-times* [thunk times]
(let [res (first (drop-while #{::fail}
(repeatedly times
#(try (thunk)
(catch Throwable _ ::fail)))))]
(when-not (= ::fail res)
res)))
Run Code Online (Sandbox Code Playgroud)
并保留try-times宏.
如果你想允许thunk返回nil,你可以删除let/when对,let :: fail表示"函数失败n次",而nil表示"函数返回nil".这种行为会更灵活但不太方便(调用者必须检查:: fail以查看它是否有效而不仅仅是nil),所以最好将它作为可选的第二个参数实现:
(defn try-times* [thunk n & fail-value]
(first (drop-while #{fail-value} ...)))
Run Code Online (Sandbox Code Playgroud)
一个try-times
宏是优雅的,但对于一个一次性的,只是拉你when
的出try
块:
(loop [tries 10]
(when (try
(might-throw-exception)
false ; so 'when' is false, whatever 'might-throw-exception' returned
(catch Exception e
(pos? tries)))
(recur (dec tries))))
Run Code Online (Sandbox Code Playgroud)