我正在寻找一种模式来处理伪代码中如下所示的代码:
do:
try planA()
catch LikelyError e:
try planB()
catch Error e:
print ("we're hosed, there is no planC()")
在 swift 中,将 try- 放入 catch {} block 中并不能如上所示工作,相反,它似乎需要嵌套到自己的 do {} block 中。看起来像这样:
enum ForeseenError : Error {
case likelyProblem
case unlikelyProblem
}
func planA () throws {
print ("planA")
throw ForeseenErrors.likelyProblem
}
func planB () throws {
print ("planB")
throw ForeseenErrors.unlikelyProblem
}
print ("Hello")
do {
try planA()
}
catch let error as ForeseenError {
print ("catch problem, trying planB")
do {
try planB()
}
catch let error {
print ("Unrecoverable error from planB")
/* if i had a planC() that potentially throws, then i'd
have to put it here in yet another nested do-try-catch
control flow structure */
}
}
catch let error {
print ("Unrecoverable error from planA")
}
print ("EOM")
对我来说,这感觉像是一种反模式,因为它需要任意深度的嵌套来处理更多的选择。此外,虽然我可能需要不同的处理程序来处理尝试序列中不同深度的不可恢复错误,但一般来说,在最终的 catch block 中捕获所有错误会更有意义。
那么社区,针对上述逻辑我们可以做些什么呢?
最佳答案
您可以使用自定义 .catch
操作定义自己的可链接类型来解决此问题,并使用您自己的名为 attempt
的类似 try 的函数创建一个实例,如下所示以下内容:
class ChainableResult {
let error: Error? // could also use Result<T, Error> in a generics setting
init(error: Error?) {
self.error = error
}
}
func attempt(_ body: () throws -> ()) -> ChainableResult {
do {
try body()
return ChainableResult(error: nil)
} catch {
return ChainableResult(error: error)
}
}
extension ChainableResult {
@discardableResult // <- dangerous
func `catch`(_ body: (Error) throws -> ()) -> ChainableResult {
if let originalError = self.error {
do {
try body(originalError)
return ChainableResult(error: originalError)
} catch {
let newError = error
return ChainableResult(error: newError)
}
} else {
return ChainableResult(error: nil)
}
}
}
然后您可以使用这些结构,如下所示:
attempt {
try planA()
}.catch {
err in
try planB()
}.catch {
err in
print("I give up")
}
我将 @discardableResult
注释为危险的,因为它允许您编写最终的 catch 操作可能抛出的链,在这种情况下,抛出的错误将得不到处理并被忽略。
最终,我写了自己的library for this 。它可以防止像我提到的那样的危险情况,并且也可以与异步函数体一起使用。我上面给出的示例用法片段可以逐字复制并编译。
关于swift - 串行链接 do-try-catch 控制流的正确模式是什么?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/44742703/