Swift 在延迟块中传播异常的正确方法
在下面的示例中,函数Swift 在延迟块中传播异常的正确方法,swift,exception-handling,Swift,Exception Handling,在下面的示例中,函数usingTemporaryDirectory()创建并删除一个临时目录,并在其间调用传递的函数body()。如果异常由createTemporaryDirectory()或传递的函数body()引发,则会传播到调用方。但是removeDirectory()引发的异常无法传递给调用者,因为任何异常都不能逃脱defer块 import Foundation func createTemporaryDirectory() throws -> URL { ... } fu
usingTemporaryDirectory()
创建并删除一个临时目录,并在其间调用传递的函数body()
。如果异常由createTemporaryDirectory()
或传递的函数body()
引发,则会传播到调用方。但是removeDirectory()
引发的异常无法传递给调用者,因为任何异常都不能逃脱defer
块
import Foundation
func createTemporaryDirectory() throws -> URL { ... }
func removeDirectory(_ url: URL) throws { ... }
func usingTemporaryDirectory(body: (URL) throws -> ()) throws {
let tempDir = try createTemporaryDirectory()
defer {
// Errors thrown from here are not handled.
try removeDirectory(tempDir)
}
try body(tempDir)
}
处理此类异常的正确方法是什么?我看到两种选择:
defer
块中引发的异常可以作为抑制异常添加到body()
引发的异常(如果有)中。斯威夫特有类似的特征吗
在这种情况下,可以将延迟块中引发的异常作为抑制异常添加到由body()
引发的异常(如果有)中。斯威夫特有类似的特征吗
据我所知并非如此——不过,你可以自己建造类似的东西。首先,让我们定义一个Error
类型,它可以存储多个底层错误:
struct ErrorCollection : Error {
private var errors: [Error] = []
init() {}
init<S : Sequence>(_ sequence: S) where S.Element == Error {
for error in sequence {
append(error)
}
}
mutating func append(_ error: Error) {
switch error {
case let x as ErrorCollection: // ensure we flatten out any nested error collections.
errors.append(contentsOf: x.errors)
case let x:
errors.append(x)
}
}
}
extension ErrorCollection : RandomAccessCollection {
typealias Index = Int
typealias Element = Error
var startIndex: Index { return errors.startIndex }
var endIndex: Index { return errors.endIndex }
func index(_ i: Index, offsetBy n: Index) -> Index {
return errors.index(i, offsetBy: n)
}
subscript(index: Index) -> Element { return errors[index] }
}
然后,您可以这样使用:
func usingTemporaryDirectory<R>(body: (URL) throws -> R) throws -> R {
let tempDir = try createTemporaryDirectory()
return try Result { try body(tempDir) }
.then { try removeDirectory(tempDir) }
.materialize()
}
func使用临时目录(body:(URL)throws->R)throws->R{
让tempDir=try createTemporaryDirectory()
返回try结果{try body(tempDir)}
。然后{尝试远程目录(tempDir)}
.具体化
}
func usingTemporaryDirectory<R>(body: (URL) throws -> R) throws -> R {
let tempDir = try createTemporaryDirectory()
return try Result { try body(tempDir) }
.then { try removeDirectory(tempDir) }
.materialize()
}