目前,无法在`try`块跨过执行recur
(let [RETRIABLE-FUNCTION (fn [] (println "Function called") (throw (ex-info "Function failed" {})))]
(loop [retries 3]
(try
(RETRIABLE-FUNCTION)
(catch Exception ex
(when (< 1 retries)
(recur (dec retries)))))))
Syntax error (UnsupportedOperationException) compiling recur at (src/repl.clj:7:13). Can only recur from tail position
因此,人们不得不将代码重写为类似于以下内容
(let [RETRIABLE-FUNCTION (fn [] (println "Function called") (throw (ex-info "Function failed" {})))]
(loop [retries 3]
(let [result (try
(RETRIABLE-FUNCTION)
(catch Exception ex
(when (< 1 retries)
::retry)))]
(if (= ::retry result)
(recur (dec retries))
result))))
这种做法相当麻烦,尤其是在嵌套重试或更复杂的状态机的情况下。
或者,可以使用许多重试宏库中的一个——我认为对于这样简单的用例来说,这是一个相当大的代价。而且通常比就地操作要少很多灵活性。
在理念上,我觉得这里应该有问题,因为`catch`块中的最后一个表达式看起来像是一个尾递归。
这是JVM的技术限制使得跨`try`执行`recur`变得不可能(或者可能是性能非常低,所以应该劝阻这样做)吗?还是它只是一个低优先级的改进用户体验的功能,所以从来没有人实现过?