swift 在根任务中抛出错误

hm2xizp9  于 2023-05-16  发布在  Swift
关注(0)|答案(2)|浏览(123)

我在文档中找不到以下行为的定义

// task-less context
Task.detached {
    try await myThrowingFunction()
    runWhenSuccessful()
}

该方法在抛出行上返回并丢弃错误,runWhenSuccessful()将永远不会被调用。虽然它在某种程度上是有意义的,但我至少期望它会触发Assert失败或未处理错误。
既然我不能处理任何父任务中的错误,那么正确的处理方法是什么呢?
我是否每次都要将闭包中的所有内容 Package 在do/catch中?

bjp0bcyl

bjp0bcyl1#

由于某些原因,Task被设计为在闭包内部抛出任何错误时静默失败。任务确实有一个result属性,当任务完成时,您可以读取它,但根据文档,它将阻塞执行它的当前线程。
我的首选解决方案是为Task创建一个方便的初始化器,它接受一个失败闭包。
这是我的自定义初始化器的样子,以及它的使用方式:

extension Task where Failure == Never, Success == Void {
    init(priority: TaskPriority? = nil, operation: @escaping () async throws -> Void, `catch`: @escaping (Error) -> Void) {
        self.init(priority: priority) {
            do {
                _ = try await operation()
            } catch {
                `catch`(error)
            }
        }
    }
}

Task {
    try await asyncTask()
} catch: { error in
    handle(error)
}
ep6jt1vc

ep6jt1vc2#

虽然还没有正式提出(* 读者:如果你想的话就请吧!* ),有talk on the Swift forums,只允许Task<Void, Never>是“@discardableResult”将是一个足够好的解决方案的问题。
现在,Task.initTask.detached始终是discardable。如果不是这样,那么“Result … is unused”消息将使程序员意识到需要采取进一步的行动……
...例如,当任务的Success不是Void...

_ = Task { "🔮" }

...或被轻推以存储任务,并在以后处理错误。

let task = // Task<Void, Error>
  Task.detached {
    try await myThrowingFunction()
    runWhenSuccessful()
  }

await task.value // Property access can throw but is not marked with 'try'

我支持这项拟议的改变。但是,仍然可以像现在这样,使用下划线忽略一个错误完成的任务,我不认为下划线很好地代表了意图:

_ = Task.detached {
  try await myThrowingFunction()
  runWhenSuccessful()
}

强制处理错误的唯一方法是让operation闭包不会使用显式的Never抛出类型系统。
invalid conversion from throwing function of type '@Sendable () async throws -> ()' to non-throwing function type '@Sendable () async -> ()'

Task<_, Never>.detached {
  try await myThrowingFunction()
  runWhenSuccessful()
}

do/catch

Task<_, Never>.detached {
  do {
    try await myThrowingFunction()
    runWhenSuccessful()
  } catch { }
}

显式的Error可能比_ = Task更能表达意图:

Task<_, Error>.detached {
  try await myThrowingFunction()
  runWhenSuccessful()
}

相关问题