英文:
Swift Task extension: Success == Sendable, Failure == Error necessary?
问题
在苹果文档中看到 `Task` 被定义为:
```swift
@frozen struct Task<Success, Failure> where Success : Sendable, Failure : Error
我看到很多在线代码中,人们会为 Task
添加像这样的扩展约束:
extension Task where Failure == Error {}
以及
extension Task where Success == Sendable {}
例如,这里 的代码通过添加约束 Failure == Error
扩展了 Task
。鉴于 Task
被定义为约束 Failure: Error
,我想知道为什么需要添加 Failure == Error
的具体原因。
谢谢!
<details>
<summary>英文:</summary>
Seeing in the Apple doc that the `Task` is defined as:
```swift
@frozen struct Task<Success, Failure> where Success : Sendable, Failure : Error
I've seen a number of code online where people add extensions to Task
with constraint like:
extension Task where Failure == Error {}
and/or
extension Task where Success == Sendable {}
For example, the code here extends Task
with the constraint Failure == Error
. Given that Task
is defined with constraint Failure: Error
I wonder what's the specific need for adding Failure == Error
?
Thanks!
答案1
得分: 1
一种类型满足 : Error
约束,如果它符合 Error
。例如,这个类型:
enum MyError: Error {
case somethingBadHappened
}
然而,MyError
不满足 == Error
约束,因为满足这个约束的唯一类型是 Error
本身。毕竟它说的是 "等于" Error
。
你可以将相同的逻辑应用到 Sendable
上。
Task.init
和 Task.detached
的版本,它们接受一个可抛出闭包,以及你链接的代码中的 relayResult
,都需要 == Error
,因为它们都从可抛出闭包创建任务。
你不知道可抛出闭包将会抛出什么特定类型的 Error
。你唯一知道的是它会抛出 Error
。因此,这些方法只能创建一个失败类型完全是 Error
的任务。它们不能创建一个失败类型是,比如,MyError
的任务,
// 假设允许使用 Failure 为 MyError 调用 Task.init
Task<SomeSuccessType, MyError> {
// 一些会抛出 AnotherError 的代码
}
因为可抛出闭包可以抛出 AnotherError
。
但假设“抛出其他类型的错误”问题以某种方式被神奇地处理,== Error
也作为编译器在调用这些方法时推断 Failure
类型的简单方法。你不需要显式地写出任务可以抛出的错误类型,就像我上面所做的那样。
我暂时想不到你何时会 正好 将 Sendable
用作 Success
类型。这似乎并不非常有用。
Sendable
没有任何语法要求,因此它在功能上与将 Void
(也称为 ()
,并符合 Sendable
)正好用作 Success
类型相同,以表示 "这个任务只是 "完成",没有结果"。如果我要选择的话,我肯定会选择 Void
而不是 Sendable
来表达这个想法。
英文:
A type satisfies the : Error
constraint if it conforms to Error
. For example, this type:
enum MyError: Error {
case somethingBadHappened
}
However, MyError
does not satisfy an == Error
constraint, because the only type that satisfies this constraint is Error
itself. It says "equal to" Error
, after all
You can apply the same logic to Sendable
.
The versions of Task.init
and Task.detached
that take a throwing closure, and relayResult
in your linked code, all requires == Error
, because they all create tasks from a throwing closure.
You don't know what specific type of Error
a throwing closure is going to throw. The best you know is it throws Error
. Therefore, these methods can only create a task whose failure type is exactly Error
. They cannot create a task whose failure type is, say, MyError
,
// let's say that calling Task.init with Failure being MyError is allowed
Task<SomeSuccessType, MyError> {
// some code that throws AnotherError
}
because the throwing closure can throw AnotherError
.
But let's say the "throwing other types of errors" problem is magically handled somehow, this == Error
also serves as an easy way for the compiler to infer the Failure
type when you call these methods. You don't need to write the type of error the task can throw explicitly, like I did above.
I can't think of when you would use exactly Sendable
as the Success
type off the top of my head though. That doesn't seem very useful.
Sendable
doesn't have any syntactic requirements, so it is functionally the same as using exactly Void
(aka ()
, and also conforms to Sendable
) as the Success
type, to indicate "this task just "finishes" and has no result". If I were to choose, I would definitely choose Void
instead of Sendable
to express this idea.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论