mirror of
https://github.com/SwiftGGTeam/the-swift-programming-language-in-chinese
synced 2025-07-06 21:55:47 +00:00
更新部分内容到 Swift 5.7 (#1200)
* 更新内容到 Swift 5.7 * 更新内容到 Swift 5.7 * 更新内容到 Swift 5.7 * update to Swift version 5.7 * 更新内容到 Swift 5.7 * 更新内容到 Swift 5.7 * 修正部分术语 * 更新内容到 Swift 5.7 * 更新内容到 Swift 5.7 * 标题格式修改 * 修改了部分用词 * 修改了代码块格式 * 修改了代码段及行内代码格式 * 修改了代码段及行内代码样式 * 按照排版要求重新修改了部分格式 * Delete 02_Lexical_Structure.md * Delete 03_Types.md * Delete 04_Expressions.md * Delete 05_Statements.md * Delete 07_Attributes.md * Delete 10_Summary_of_the_Grammar.md * 根据排版指南修改了部分格式 * 根据排版指南修改了部分格式 * Update source/03_language_reference/02_Lexical_Structure.md Co-authored-by: Jie Liang <lj925184928@gmail.com>
This commit is contained in:
BIN
document/TheSwiftProgrammingLanguageSwift57.epub
Normal file
BIN
document/TheSwiftProgrammingLanguageSwift57.epub
Normal file
Binary file not shown.
@ -1,13 +1,13 @@
|
||||
# 版本兼容性
|
||||
|
||||
本书描述的是在 Xcode 13 中默认包含的 Swift 5.5 版本。你可以使用 Xcode 13 来构建 Swift 5.5、Swift 4.2 或 Swift 4 写的项目。
|
||||
本书描述的是在 Xcode 14 中默认包含的 Swift 5.7 版本。你可以使用 Xcode 14 来构建 Swift 5.7、Swift 4.2 或 Swift 4 写的项目。
|
||||
|
||||
使用 Xcode 13 构建 Swift 4 和 Swift 4.2 代码时,Swift 5.5 的大多数功能都适用。但以下功能仅支持 Swift 5.5 或更高版本:
|
||||
使用 Xcode 14 构建 Swift 4 和 Swift 4.2 代码时,Swift 5.7 的大多数功能都适用。但以下功能仅支持 Swift 5.7 或更高版本:
|
||||
|
||||
* 返回值是不透明类型的函数依赖 Swift 5.1 运行时。
|
||||
* **try?** 表达式不会为已返回可选类型的代码引入额外的可选类型层级。
|
||||
* 大数字的整型字面量初始化代码的类型将会被正确推导,例如 **UInt64(0xffff_ffff_ffff_ffff)** 将会被推导为整型类型而非溢出。
|
||||
|
||||
并发特性需要 Swift 5.5 及以上版本,以及一个提供了并发相关类型的 Swift 标准库版本。要应用于苹果平台,请至少将部署版本设置为 iOS 15、macOS 12、tvOS 15 或 watchOS 8.0。
|
||||
并发特性需要 Swift 5.7 及以上版本,以及一个提供了并发相关类型的 Swift 标准库版本。要应用于苹果平台,请至少将部署版本设置为 iOS 15、macOS 12、tvOS 15 或 watchOS 8.0。
|
||||
|
||||
用 Swift 5.5 写的项目可以依赖用 Swift 4.2 或 Swift 4 写的项目,反之亦然。这意味着,如果你将一个大的项目分解成多个框架(framework),你可以逐个地将框架从 Swift 4 代码迁移到 Swift 5.5。
|
||||
用 Swift 5.7 写的项目可以依赖用 Swift 4.2 或 Swift 4 写的项目,反之亦然。这意味着,如果你将一个大的项目分解成多个框架(framework),你可以逐个地将框架从 Swift 4 代码迁移到 Swift 5.7。
|
||||
|
@ -154,6 +154,14 @@ let fullName: String = "John Appleseed"
|
||||
let informalGreeting = "Hi \(nickName ?? fullName)"
|
||||
```
|
||||
|
||||
你还可以使用较短的代码解包一个值,并且对该被包装值使用相同的名称。
|
||||
|
||||
```swift
|
||||
if let nickname {
|
||||
print("Hey, \(nickName)")
|
||||
}
|
||||
```
|
||||
|
||||
`switch` 支持任意类型的数据以及各种比较操作——不仅仅是整数以及测试相等。
|
||||
|
||||
```swift
|
||||
@ -613,6 +621,51 @@ let threeOfSpadesDescription = threeOfSpades.simpleDescription()
|
||||
>
|
||||
> 写一个方法,创建一副完整的扑克牌,这些牌是所有 rank 和 suit 的组合。
|
||||
|
||||
## 并发性 {#concurrency}
|
||||
|
||||
使用 `async` 标记异步运行的函数
|
||||
|
||||
```swift
|
||||
func fetchUserID(from server: String) async -> Int{
|
||||
if server == "primary"
|
||||
return 97
|
||||
}
|
||||
return 501
|
||||
```
|
||||
|
||||
您还可以通过在函数名前添加 `await` 来标记对异步函数的调用
|
||||
|
||||
```swift
|
||||
func fetchUsername(from server:String) async -> String{
|
||||
let userID = await fetchUserID(from: server)
|
||||
if userID == 501{
|
||||
return "John Appleseed"
|
||||
}
|
||||
return "Guest"
|
||||
}
|
||||
```
|
||||
|
||||
使用 `async let` 来调用异步函数,并让其与其它异步函数并行运行。
|
||||
使用 `await` 以使用该异步函数返回的值。
|
||||
|
||||
```swift
|
||||
func connectUser(to server: String) async{
|
||||
async let userID = fetchUserID(from: server)
|
||||
async let username = fetchUsername(from: server)
|
||||
let greeting = await "Hello \(username), user ID \(userID)"
|
||||
print(greeting)
|
||||
}
|
||||
```
|
||||
|
||||
使用 `Task` 从同步代码中调用异步函数且不等待它们返回结果
|
||||
|
||||
```swift
|
||||
Task {
|
||||
await connectUser(to: "primary")
|
||||
}
|
||||
//Prints "Hello Guest, user ID 97"
|
||||
```
|
||||
|
||||
## 协议和扩展 {#protocols-and-extensions}
|
||||
|
||||
使用 `protocol` 来声明一个协议。
|
||||
|
@ -587,16 +587,38 @@ if let actualNumber = Int(possibleNumber) {
|
||||
|
||||
如果转换成功,`actualNumber` 常量可以在 `if` 语句的第一个分支中使用。它已经被可选类型 *包含的* 值初始化过,所以不需要再使用 `!` 后缀来获取它的值。在这个例子中,`actualNumber` 只被用来输出转换结果。
|
||||
|
||||
你可以在可选绑定中使用常量和变量。如果你想在 `if` 语句的第一个分支中操作 `actualNumber` 的值,你可以改成 `if var actualNumber`,这样可选类型包含的值就会被赋给一个变量而非常量。
|
||||
如果你在访问它包含的值后不需要引用原来的可选常量或是可选变量,你可以对新的常量或是新的变量使用相同的名称:
|
||||
|
||||
你可以包含多个可选绑定或多个布尔条件在一个 `if` 语句中,只要使用逗号分开就行。只要有任意一个可选绑定的值为 `nil`,或者任意一个布尔条件为 `false`,则整个 `if` 条件判断为 `false`。下面的两个 `if` 语句是等价的:
|
||||
```swift
|
||||
let myNumber = Int(possibleNumber)
|
||||
// 此处 myNumber 为一可选整型
|
||||
if let myNumber = myNumber {
|
||||
// 此处 myNumber 为一不可选整型
|
||||
print("My number is \(myNumber)")
|
||||
}
|
||||
// 输出 "My number is 123"
|
||||
```
|
||||
|
||||
正如前一个例子中的代码一样,本例代码首先检查 `myNumber` 是否包含任何值。若 `myNumber` 包含有任何值,则该值将成为新常量 `myNumber` 的值。在 `if` 语句的主体中,写入的 `myNumber` 指向这一个新的非可选常量。在 `if` 语句开始前和语句结束后,写入的 `myNumber` 指向可选的整数常量。
|
||||
|
||||
由于这种代码非常常见,你可以通过一个更简短的写法来解包一个可选值:只写你要展开的常量或变量的名称。新的常量/变量将使用相同的名称作为其隐式解包可选值。
|
||||
|
||||
``` swift
|
||||
if let myNumber{
|
||||
print("My number is \(muNumber)")
|
||||
}
|
||||
// 输出 "My number is 123"
|
||||
```
|
||||
|
||||
你可以在可选绑定中使用常量和变量。如果你想在 `if` 语句的第一个分支中操作 `actualNumber` 的值,你可以改成 `if var actualNumber`,这样可选类型包含的值就会被赋给一个变量而非常量。你在 `if` 语句中对 `myNumber` 所做的更改将仅作用于该局部变量而非你解包的原始可选常量/变量。
|
||||
|
||||
你可以包含多个可选绑定或多个布尔条件在一个 `if` 语句中,只要使用逗号分开就行。只要有任意一个可选绑定的值为 `nil`,或者任意一个布尔条件为 `false`,则整个 `if` 条件判断为 `false`。下面的两个 `if` 语句是等效的:
|
||||
|
||||
```swift
|
||||
if let firstNumber = Int("4"), let secondNumber = Int("42"), firstNumber < secondNumber && secondNumber < 100 {
|
||||
print("\(firstNumber) < \(secondNumber) < 100")
|
||||
}
|
||||
// 输出“4 < 42 < 100”
|
||||
|
||||
if let firstNumber = Int("4") {
|
||||
if let secondNumber = Int("42") {
|
||||
if firstNumber < secondNumber && secondNumber < 100 {
|
||||
|
@ -16,7 +16,7 @@ Swift 还提供了 C 语言没有的区间运算符,例如 `a..<b` 或 `a...b`
|
||||
- *二元*运算符操作两个操作对象(如 `2 + 3`),是*中置*的,因为它们出现在两个操作对象之间。
|
||||
- *三元*运算符操作三个操作对象,和 C 语言一样,Swift 只有一个三元运算符,就是三目运算符(`a ? b : c`)。
|
||||
|
||||
受运算符影响的值叫*操作数*,在表达式 `1 + 2` 中,加号 `+` 是二元运算符,它的两个操作数是值 `1` 和 `2`。
|
||||
受运算符影响的值叫*操作数*,在表达式 `1 + 2` 中,加号 `+` 是中置运算符,它的两个操作数是值 `1` 和 `2`。
|
||||
|
||||
## 赋值运算符 {#assignment-operator}
|
||||
|
||||
|
@ -765,3 +765,35 @@ if #available(平台名称 版本号, ..., *) {
|
||||
APIs 不可用,使用先前版本API的语句将执行
|
||||
}
|
||||
```
|
||||
|
||||
当你在 `guard` 语句中使用可用性条件时,它将细化用于该代码块中其余代码的可用性信息。
|
||||
|
||||
```swift
|
||||
@avaliable(macOS 10.12, *)
|
||||
struct ColorPreference {
|
||||
var bestColor = "blue"
|
||||
}
|
||||
func chooseBestColor() -> String {
|
||||
guard #avaliable(macOS 10.12, *) else{
|
||||
return "gray"
|
||||
}
|
||||
let colors = ColorPreference()
|
||||
return colors.bestColor
|
||||
}
|
||||
```
|
||||
|
||||
在上面的例子中,结构体 `ColorPreference` 需要 macOS 10.12 或更高的版本。函数 `ChooseBestColor()` 先以一个可用性防护开头,若平台版本过低无法运行 `ColorPreference` 时,将执行该低版本平台可用的行为。而在 `guard` 语句后,你将能够使用 macOS 10.12 或更高版本的API。
|
||||
|
||||
除了 `#available` 以外, Swift 还支持通过不可用性条件来进行不可用性检查。举例如下,两种检查都能实现同样的效果:
|
||||
|
||||
```swift
|
||||
if #available(iOS 10, *){
|
||||
} else {
|
||||
//回滚代码
|
||||
}
|
||||
if #unavailable(iOS 10) {
|
||||
//回滚代码
|
||||
}
|
||||
```
|
||||
|
||||
若可用性检查只提供了回滚代码,改用用 `#unavailable` 能提升程序整体的可读性。
|
@ -225,6 +225,9 @@ print(anotherGreeting(for: "Dave"))
|
||||
|
||||
正如你将会在 [简略的 Getter 声明](./10_Properties.md) 里看到的, 一个属性的 getter 也可以使用隐式返回的形式。
|
||||
|
||||
>注意
|
||||
|
||||
>作为隐式返回值编写的代码需要返回一些值。例如,你不能使用 `print(13)` 作为隐式返回值。然而,你可以使用不返回值的函数(如 `fatalError("Oh no!")`)作为隐式返回值,因为 Swift 知道它们并不会产生任何隐式返回。
|
||||
|
||||
## 函数参数标签和参数名称 {#Function-Argument-Labels-and-Parameter-Names}
|
||||
|
||||
|
@ -214,6 +214,35 @@ let strings = numbers.map {
|
||||
|
||||
在上面的例子中,通过尾随闭包语法,优雅地在函数后封装了闭包的具体功能,而不再需要将整个闭包包裹在 `map(_:)` 方法的括号内。
|
||||
|
||||
如果一个函数接受多个闭包,您需要省略第一个尾随闭包的参数标签,并为其余尾随闭包添加标签。例如,以下函数将为图片库加载一张图片:
|
||||
|
||||
```swift
|
||||
func loadPicture(from server: Server, completion:(Picture) -> Void,
|
||||
onFailure: () -> Void) {
|
||||
if let picture = download("photo.jpg", from: server){
|
||||
completion(picture)
|
||||
}else{
|
||||
onFailure()
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
当您调用该函数以加载图片时,需要提供两个闭包。第一个闭包是一个完成处理程序,它在成功下载后加载图片;第二个闭包是一个错误处理程序,它向用户显示错误。
|
||||
|
||||
```swift
|
||||
loadPicture(from: someServer){ picture in
|
||||
someView.currentPicture = picture
|
||||
} onFailure: {
|
||||
print("Couldn't download the next picture.")
|
||||
}
|
||||
```
|
||||
|
||||
在本例中,`loadPicture(from:completion:onFailure:)` 函数将它的网络任务分配到后台,并在网络任务完成时调用两个完成处理程序中的一个。通过这种方法编写函数,您将能够把负责处理网络故障的代码和成功下载后更新用户界面的代码干净地区分开,而不是只使用一个闭包处理两种情况。
|
||||
|
||||
>注意
|
||||
>
|
||||
>完成处理程序可能很难阅读,特别是您必须嵌套多个完成处理程序时。另一种方法是使用异步代码,如章节[并发](./28_Concurrency.md#function-types-as-return-types) 中所述。
|
||||
|
||||
## 值捕获 {#capturing-values}
|
||||
|
||||
闭包可以在其被定义的上下文中*捕获*常量或变量。即使定义这些常量和变量的原作用域已经不存在,闭包仍然可以在闭包函数体内引用和修改这些值。
|
||||
|
@ -132,6 +132,7 @@ struct Rect {
|
||||
var square = Rect(origin: Point(x: 0.0, y: 0.0),
|
||||
size: Size(width: 10.0, height: 10.0))
|
||||
let initialSquareCenter = square.center
|
||||
// initialSquareCenter 位于(5.0, 5.0)
|
||||
square.center = Point(x: 15.0, y: 15.0)
|
||||
print("square.origin is now at (\(square.origin.x), \(square.origin.y))")
|
||||
// 打印“square.origin is now at (10.0, 10.0)”
|
||||
@ -302,7 +303,7 @@ struct TwelveOrLess {
|
||||
}
|
||||
```
|
||||
|
||||
这个 setter 确保新值小于 12,而且返回被存储的值。
|
||||
这个 setter 确保新值小于或等于 12,而且返回被存储的值。
|
||||
> 注意
|
||||
>
|
||||
> 上面例子以 `private` 的方式声明 `number` 变量,这使得 `number` 仅在 `TwelveOrLess` 的实现中使用。写在其他地方的代码通过使用 `wrappedValue` 的 getter 和 setter 来获取这个值,但不能直接使用 `number`。有关 `private` 的更多信息,请参考 [访问控制](./26_Access_Control.md)
|
||||
|
@ -535,7 +535,7 @@ print("Bicycle: \(bicycle.description)")
|
||||
// 打印“Bicycle: 2 wheel(s)”
|
||||
```
|
||||
|
||||
如果子类的构造器没有在阶段 2 过程中做自定义操作,并且父类有一个无参数的指定构造器,你可以在所有子类的存储属性赋值之后省略 `super.init()` 的调用。
|
||||
如果子类的构造器没有在阶段 2 过程中做自定义操作,并且父类有一个同步、无参数的指定构造器,你可以在所有子类的存储属性赋值之后省略 `super.init()` 的调用。若父类有一个异步的构造器,你就需要明确地写入 `await super.init()`。
|
||||
|
||||
这个例子定义了另一个 `Vehicle` 的子类 `Hoverboard` ,只设置它的 `color` 属性。这个构造器依赖隐式调用父类的构造器来完成,而不是显示调用 `super.init()`。
|
||||
|
||||
|
@ -276,7 +276,7 @@ signedOverflow = signedOverflow &- 1
|
||||
|
||||
类和结构体可以为现有的运算符提供自定义的实现。这通常被称为运算符*重载*。
|
||||
|
||||
下面的例子展示了如何让自定义的结构体支持加法运算符(`+`)。算术加法运算符是一个*二元运算符*,因为它是对两个值进行运算,同时它还可以称为*中缀*运算符,因为它出现在两个值中间。
|
||||
下面的例子展示了如何让自定义的结构体支持加法运算符(`+`)。算术加法运算符是一个二元运算符,因为它是对两个值进行运算,同时它还可以称为中缀运算符,因为它出现在两个值中间。
|
||||
|
||||
例子中定义了一个名为 `Vector2D` 的结构体用来表示二维坐标向量 `(x, y)`,紧接着定义了一个可以将两个 `Vector2D` 结构体实例进行相加的*运算符函数*:
|
||||
|
||||
|
@ -7,7 +7,7 @@ Swift 对于结构化的编写异步和并行代码有着原生的支持。异
|
||||
|
||||
> 注意
|
||||
>
|
||||
> 如果你曾经写过并发的代码的话,那可能使用过线程。Swift 中的并发模型是基于线程的,但你不会直接和线程打交道。在 Swift 中,一个异步函数可以交出它在某个线程上的运行权,这样另一个异步函数在这个函数被阻塞时就能获得此线程的运行权。
|
||||
> 如果你曾经写过并发的代码的话,那可能使用过线程。Swift 中的并发模型是基于线程的,但你不会直接和线程打交道。在 Swift 中,一个异步函数可以交出它在某个线程上的运行权,这样另一个异步函数在这个函数被阻塞时就能获得此线程的运行权。但是,Swift并不能确定当异步函数恢复运行时其将在哪条线程上运行。
|
||||
|
||||
你当然也可以不用 Swift 原生支持去写并发的代码,只不过代码的可读性会下降。比如,下面的这段代码会拉取一系列图片名称的列表,下载列表中的图片然后展示给用户:
|
||||
|
||||
@ -64,19 +64,42 @@ show(photo)
|
||||
|
||||
* 异步函数,方法或变量内部的代码
|
||||
* 静态函数 `main()` 中被打上 `@main` 标记的结构体、类或者枚举中的代码
|
||||
* 游离的子任务中的代码,之后会在[非结构化并行](#Unstructured-Concurrency)中说明
|
||||
* 非结构化的子任务中的代码,之后会在 [非结构化并行](#Unstructured-Concurrency) 中说明
|
||||
|
||||
在可能的悬点之间的代码将按顺序运行,并不可能被其它并发代码中断。例如,以下代码将一张图片从一个图库移动到另一个图库:
|
||||
|
||||
```swift
|
||||
let firstPhoto = await listPhotos(inGallery: "Summer Vacation")[0]
|
||||
add(firstPhoto toGallery: "Road Trip")
|
||||
//此时,firstPhoto暂时地同时存在于两个画廊中
|
||||
remove(firstPhoto fromGallery: "Summer Vacation")
|
||||
```
|
||||
|
||||
其它代码不能在 `add(_:toGallery:)` 和 `remove(_:fromGallery:)` 两个方法之间运行。在此期间,第一张图片同时存在于两个图库,暂时打破了应用程序的一个不变量。为了更明确地表示这段代码不能加入 `await` 标记,你可以将这段代码重构为一个同步函数:
|
||||
|
||||
```swift
|
||||
func move(_photoName: String, from source: String, to destination: String) {
|
||||
add(photoName, to: destination)
|
||||
remove(photoName, from: source)
|
||||
}
|
||||
//...
|
||||
let firstPhoto = await listPhotos(inGallery: "Summer Vacation")[0]
|
||||
move(firstPhoto, from: "Summer Vacation", to: "Road Trip")
|
||||
```
|
||||
|
||||
在上例中,由于 `move(_:from:to:)` 函数为同步函数,你将能够保证它将不会包含潜在的悬点。在未来,试图在该函数中写入并发代码将引发编译错误而非产生bug。
|
||||
|
||||
> 注意
|
||||
>
|
||||
> 学习并行的过程中,[Task.sleep(_:)](https://developer.apple.com/documentation/swift/task/3814836-sleep) 方法非常有用。这个方法什么都没有做,只是等待不少于指定的时间(单位纳秒)后返回。下面是使用 `sleep()` 方法模拟网络请求实现 `listPhotos(inGallery:)` 的一个版本:
|
||||
> 学习并行的过程中,[Task.sleep(_:)](https://developer.apple.com/documentation/swift/task/3814836-sleep) 方法非常有用。这个方法什么都没有做,只是等待不少于指定的时间(单位纳秒)后返回。下面是使用 `sleep(until:clock:)` 方法模拟网络请求实现 `listPhotos(inGallery:)` 的一个版本:
|
||||
>
|
||||
|
||||
```Swift
|
||||
func listPhotos(inGallery name: String) async -> [String] {
|
||||
await Task.sleep(2 * 1_000_000_000) // 两秒
|
||||
return ["IMG001", "IMG99", "IMG0404"]
|
||||
```swift
|
||||
func listPhotos(inGallery name: String) async throws -> [String] {
|
||||
try await Task.sleep(until: .now + .seconds(2), clock: .continuous)
|
||||
return ["IMG001", "IMG99", "IMG0404"]
|
||||
}
|
||||
```
|
||||
```
|
||||
|
||||
## 异步序列 {#Asynchronous-Sequences}
|
||||
|
||||
@ -142,7 +165,7 @@ show(photos)
|
||||
await withTaskGroup(of: Data.self) { taskGroup in
|
||||
let photoNames = await listPhotos(inGallery: "Summer Vacation")
|
||||
for name in photoNames {
|
||||
taskGroup.async { await downloadPhoto(named: name) }
|
||||
taskGroup.addTask { await downloadPhoto(named: name) }
|
||||
}
|
||||
}
|
||||
```
|
||||
@ -151,15 +174,16 @@ await withTaskGroup(of: Data.self) { taskGroup in
|
||||
|
||||
### 非结构化并发 {#Unstructured-Concurrency}
|
||||
|
||||
对于并发来说,除了上一部分讲到的结构化的方式,Swift 还支持非结构化并发。与任务组中的任务不同的是,*非结构化任务(unstructured task)*并没有父任务。你能以任何方式来处理非结构化任务以满足你程序的需要,但与此同时,你需要对于他们的正确性付全责。如果想创建一个在当前 actor 上运行的非结构化任务,需要调用初始化方法 [Task.init(priority:operation:)](https://developer.apple.com/documentation/swift/task/3856790-init)。如果想要创建一个不在当前 actor 上运行的非结构化任务(更具体地说就是*游离任务(detached task)*),需要调用类方法 [Task.detached(priority:operation:)](https://developer.apple.com/documentation/swift/task/3856786-detached)。以上两种方法都能返回一个能让你与任务交互(继续等待结果或取消任务)的任务句柄,如下:
|
||||
对于并发来说,除了上一部分讲到的结构化的方式,Swift 还支持非结构化并发。与任务组中的任务不同的是,*非结构化任务(unstructured task)*并没有父任务。你能以任何方式来处理非结构化任务以满足你程序的需要,但与此同时,你需要对于他们的正确性付全责。如果想创建一个在当前 actor 上运行的非结构化任务,需要调用构造器 [Task.init(priority:operation:)](https://developer.apple.com/documentation/swift/task/3856790-init)。如果想要创建一个不在当前 actor 上运行的非结构化任务(更具体地说就是*游离任务(detached task)*),需要调用类方法 [Task.detached(priority:operation:)](https://developer.apple.com/documentation/swift/task/3856786-detached)。以上两种方法都能返回一个能让你与任务交互(继续等待结果或取消任务)的任务句柄,如下:
|
||||
|
||||
```Swift
|
||||
```swift
|
||||
let newPhoto = // ... 图片数据 ...
|
||||
let handle = Task {
|
||||
return await add(newPhoto, toGalleryNamed: "Spring Adventures")
|
||||
return await add(newPhoto, toGalleryNamed: "Spring Adventures")
|
||||
}
|
||||
let result = await handle.value
|
||||
```
|
||||
|
||||
如果你想更多的了解游离任务,可以参考 [Task](https://developer.apple.com/documentation/swift/task)。
|
||||
|
||||
### 任务取消 {#Task-Cancellation}
|
||||
@ -176,6 +200,8 @@ Swift 中的并发使用合作取消模型。每个任务都会在执行中合
|
||||
|
||||
## Actors {#Actors}
|
||||
|
||||
你可以使用任务来将自己的程序分割为孤立、并发的部分。任务间相互孤立,这也使得它们能够安全地同时运行。但有时你需要在任务间共享信息。Actors便能够帮助你安全地在并发代码间分享信息。
|
||||
|
||||
跟类一样,actor 也是一个引用类型,所以 [类是引用类型](https://docs.swift.org/swift-book/LanguageGuide/ClassesAndStructures.html#ID89) 中关于值类型和引用类型的比较同样适用于 actor 和类。不同于类的是,actor 在同一时间只允许一个任务访问它的可变状态,这使得多个任务中的代码与一个 actor 交互时更加安全。比如,下面是一个记录温度的 actor:
|
||||
|
||||
```Swift
|
||||
@ -231,3 +257,42 @@ print(logger.max) // 报错
|
||||
```
|
||||
|
||||
不添加 `await` 关键字的情况下访问 `logger.max` 会失败,因为 actor 的属性是它隔离的本地状态的一部分。Swift 可以保证只有 actor 内部的代码可以访问 actor 的内部状态。这个保证也被称为 *actor isolation*。
|
||||
|
||||
## 可发送类型 {#Sendable-Types}
|
||||
|
||||
任务和Actor能够帮助你将程序分割为能够安全地并发运行的小块。在一个任务中,或是在一个Actor实例中,程序包含可变状态的部分(如变量和属性)被称为*并发域(Concurrency domain)*。部分类型的数据不能在并发域间共享,因为它们包含了可变状态,但它不能阻止重叠访问。
|
||||
|
||||
能够在并发域间共享的类型被称为*可发送类型(Sendable Type)*。例如在调用Actor方法时被作为实参传递,或是作为任务的结果返回。本章之前的例子并未讨论可发送性,因为这些例子均使用了简单值类型,对于在并发域间传递的数据而言,简单值类型总是安全的。而与之相反,另一些类型并不能安全地在并发域间传递。例如,当你在不同的任务间传递该类的实例时,包含可变属性且并未序列化对这些属性的访问的类可能产生不可预测和不正确的结果。
|
||||
|
||||
你可以通过声明其符合 `Sendable` 协议来将某个类型标记为可发送类型。该协议并不包含任何代码要求,但Swift对其做出了强制的语义要求。总之,有三种方法将一个类型声明为可发送类型:
|
||||
|
||||
- 该类型为值类型,且其可变状态由其它可发送数据构成——例如具有存储属性的结构体或是具有关联值的枚举。
|
||||
|
||||
- 该类型不包含任何可变状态,且其不可变状态由其它可发送数据构成——例如只包含只读属性的结构体或类
|
||||
|
||||
- 该类型包含能确保其可变状态安全的代码——例如标记了 `@MainActor` 的类或序列化了对特定线程/队列上其属性的访问的类。
|
||||
|
||||
如需了解Swift对Sendable协议的语义要求的详细信息,请访问 [Sendable](https://developer.apple.com/documentation/swift/sendable) 协议参考。
|
||||
|
||||
部分类型总是可发送类型,如只有可发送属性的结构体和只有可发送关联值的枚举。例如:
|
||||
|
||||
```swift
|
||||
struct TemperatureReading: Sendable {
|
||||
var measurement: Int
|
||||
}
|
||||
extension TemperatureLogger {
|
||||
func addReading(from reading: TemperatureReading) {
|
||||
measurements.append(reading.measurement)
|
||||
}
|
||||
}
|
||||
let logger = TemperatureLogger(label: "Tea kettle", measurement: 85)
|
||||
let reading = TemperatureReading(measurement: 45)
|
||||
await logger.addReading(from: reading)
|
||||
```
|
||||
由于 `TemperatureReading` 是只有可发送属性的结构体,且该结构体并未被标记为 `public` 或 `@usableFromInline`,因此它是隐式可发送的。下文给出了该结构体的一个符合 `Sendable` 协议的版本:
|
||||
|
||||
```swift
|
||||
struct TemperatureReading {
|
||||
var measurement: Int
|
||||
}
|
||||
```
|
File diff suppressed because it is too large
Load Diff
@ -164,7 +164,9 @@ var operation: (Int, Int) -> Int // 正确
|
||||
|
||||
如果一个函数类型包涵多个箭头(->),那么函数类型将从右向左进行组合。例如,函数类型 `(Int) -> (Int) -> Int` 可以理解为 `(Int) -> ((Int) -> Int)`,也就是说,该函数传入 `Int`,并返回另一个传入并返回 `Int` 的函数。
|
||||
|
||||
函数类型若要抛出或重抛错误就必须使用 `throws` 关键字来标记。`throws` 关键字是函数类型的一部分,非抛出函数是抛出函数的子类型。因此,在使用抛出函数的地方也可以使用不抛出函数。抛出和重抛函数的相关描述见章节 [抛出函数与方法](./06_Declarations.md#throwing-functions-and-methods) 和 [重抛函数与方法](./06_Declarations.md#rethrowing-functions-and-methods)。
|
||||
使用函数类型的函数若要抛出或重抛错误就必须使用 `throws` 关键字来标记。`throws` 关键字是函数类型的一部分,非抛出函数是抛出函数的子类型。因此,在使用抛出函数的地方也可以使用不抛出函数。抛出和重抛函数的相关描述见章节 [抛出函数与方法](./06_Declarations.md#throwing-functions-and-methods) 和 [重抛函数与方法](./06_Declarations.md#rethrowing-functions-and-methods)。
|
||||
|
||||
异步函数的函数类型必须使用 `async` 关键字来标记。 `async` 关键字也是函数类型的一部分,且同步函数是异步函数的子类型。因此,在使用异步函数的地方也可以使用同步函数。异步函数的相关描述见章节 [异步函数和方法](Declarations.xhtml#ID647)。
|
||||
|
||||
### 对非逃逸闭包的限制 {#Restrictions for Nonescaping Closures}
|
||||
当非逃逸闭包函数是形参时,不能存储在属性、变量或任何 `Any` 类型的常量中,因为这可能导致值的逃逸。
|
||||
@ -195,7 +197,7 @@ func takesTwoFunctions(first: (Any) -> Void, second: (Any) -> Void) {
|
||||
>
|
||||
|
||||
#### function-type {#function-type}
|
||||
> *函数类型* → [特性列表](./07_Attributes.md#attributes)<sub>可选</sub> [函数类型子句](#function-type-argument-clause) **throws**<sub>可选</sub> **->** [类型](#type)
|
||||
> *函数类型* → [特性列表](./07_Attributes.md#attributes)<sub>可选</sub> [函数类型子句](#function-type-argument-clause) **async**<sub>可选</sub>**throws**<sub>可选</sub> **->** [类型](#type)
|
||||
|
||||
#### function-type-argument-clause {#function-type-argument-clause}
|
||||
> *函数类型子句* → **(** **)**
|
||||
@ -539,7 +541,7 @@ print(type(of: z.f()))
|
||||
>
|
||||
|
||||
#### type-inheritance-list {#type-inheritance-list}
|
||||
> *类型继承列表* → [类型标识符](#type-identifier) | [类型标识符](#type-identifier) **,** [类型继承列表](#type-inheritance-list)
|
||||
> *类型继承列表* → [属性](./07_Attributes.md#attributes)<sub>可选</sub> [类型标识符](#type-identifier) | [属性](./07_Attributes.md#attributes)<sub>可选</sub> [类型标识符](#type-identifier) **,** [类型继承列表](#type-inheritance-list)
|
||||
|
||||
## 类型推断
|
||||
|
||||
|
@ -1,13 +1,13 @@
|
||||
# 表达式(Expressions)
|
||||
|
||||
Swift 中存在四种表达式:前缀表达式,二元表达式,基本表达式和后缀表达式。表达式在返回一个值的同时还可以引发副作用。
|
||||
Swift 中存在四种表达式:前缀表达式,中缀表达式,基本表达式和后缀表达式。表达式在返回一个值的同时还可以引发副作用。
|
||||
|
||||
通过前缀表达式和二元表达式可以对简单表达式使用各种运算符。基本表达式从概念上讲是最简单的一种表达式,它是一种访问值的方式。后缀表达式则允许你建立复杂的表达式,例如函数调用和成员访问。每种表达式都在下面有详细论述。
|
||||
通过前缀表达式和中缀表达式可以对简单表达式使用各种运算符。基本表达式从概念上讲是最简单的一种表达式,它是一种访问值的方式。后缀表达式则允许你建立复杂的表达式,例如函数调用和成员访问。每种表达式都在下面有详细论述。
|
||||
|
||||
> 表达式语法
|
||||
|
||||
#### expression {#expression}
|
||||
> *表达式* → [try 运算符](#try-operator)<sub>可选</sub> [await 运算符](#await-operator)<sub>可选</sub> [前缀表达式](#prefix-expression) [二元表达式列表](#binary-expressions)<sub>可选</sub>
|
||||
> *表达式* → [try 运算符](#try-operator)<sub>可选</sub> [await 运算符](#await-operator)<sub>可选</sub> [前缀表达式](#prefix-expression) [中缀表达式列表](#infix-expressions)<sub>可选</sub>
|
||||
|
||||
#### expression-list {#expression-list}
|
||||
|
||||
@ -62,7 +62,7 @@ Swift 中存在四种表达式:前缀表达式,二元表达式,基本表
|
||||
|
||||
强制 try 表达式的返回值是该*表达式*的值。如果该*表达式*抛出了错误,将会引发运行时错误。
|
||||
|
||||
在二元运算符左侧的表达式被标记上 `try`、`try?` 或者 `try!` 时,这个运算符对整个二元表达式都产生作用。也就是说,你可以使用括号来明确运算符的作用范围。
|
||||
在中缀运算符左侧的表达式被标记上 `try`、`try?` 或者 `try!` 时,这个运算符对整个中缀表达式都产生作用。也就是说,你可以使用括号来明确运算符的作用范围。
|
||||
|
||||
```swift
|
||||
// try 对两个函数调用都产生作用
|
||||
@ -75,7 +75,7 @@ sum = try (someThrowingFunction() + anotherThrowingFunction())
|
||||
sum = (try someThrowingFunction()) + anotherThrowingFunction()
|
||||
```
|
||||
|
||||
`try` 表达式不能出现在二元运算符的的右侧,除非二元运算符是赋值运算符或者 `try` 表达式是被圆括号括起来的。
|
||||
`try` 表达式不能出现在中缀运算符的的右侧,除非中缀运算符是赋值运算符或者 `try` 表达式是被圆括号括起来的。
|
||||
|
||||
如果表达式中同时包含 `try` 和 `await` 运算符,`try` 运算符必须在前面。
|
||||
|
||||
@ -99,7 +99,7 @@ sum = (try someThrowingFunction()) + anotherThrowingFunction()
|
||||
|
||||
`await` 表达式只能在异步的上下文中出现,比如传入 `async(priority:operation:)` 函数的尾随闭包中。它不能在 `defer` 语句的闭包中,或者在同步函数的自动闭包中出现。
|
||||
|
||||
在二元运算符左侧的表达式被标记上 `await` 运算符时,这个运算符对整个二元表达式都产生作用。也就是说,你可以使用括号来明确运算符的作用范围。
|
||||
在中缀运算符左侧的表达式被标记上 `await` 运算符时,这个运算符对整个中缀表达式都产生作用。也就是说,你可以使用括号来明确运算符的作用范围。
|
||||
|
||||
```swift
|
||||
// await 对两个函数调用都产生作用
|
||||
@ -112,7 +112,7 @@ sum = await (someAsyncFunction() + anotherAsyncFunction())
|
||||
sum = (await someAsyncFunction()) + anotherAsyncFunction()
|
||||
```
|
||||
|
||||
`await` 表达式不能出现在二元运算符的的右侧,除非二元运算符是赋值运算符或者 `await` 表达式是被圆括号括起来的。
|
||||
`await` 表达式不能出现在中缀运算符的的右侧,除非中缀运算符是赋值运算符或者 `await` 表达式是被圆括号括起来的。
|
||||
|
||||
如果表达式中同时包含 `try` 和 `await` 运算符,`try` 运算符必须在前面。
|
||||
|
||||
@ -122,11 +122,11 @@ sum = (await someAsyncFunction()) + anotherAsyncFunction()
|
||||
> *await 运算符* → **await**
|
||||
|
||||
|
||||
## 二元表达式 {#binary-expressions}
|
||||
## 中缀表达式 {#infix-expressions}
|
||||
|
||||
*二元表达式*由中缀运算符和左右参数表达式组成。形式如下:
|
||||
*中缀表达式*由中缀运算符和左右参数表达式组成。形式如下:
|
||||
|
||||
> `左侧参数` `二元运算符` `右侧参数`
|
||||
> `左侧参数` `中缀运算符` `右侧参数`
|
||||
|
||||
关于这些运算符的更多信息,请参阅 [基本运算符](../02_language_guide/02_Basic_Operators.md) 和 [高级运算符](../02_language_guide/27_Advanced_Operators.md)。
|
||||
|
||||
@ -134,22 +134,22 @@ sum = (await someAsyncFunction()) + anotherAsyncFunction()
|
||||
|
||||
> 注意
|
||||
>
|
||||
> 在解析时,一个二元表达式将作为一个扁平列表表示,然后根据运算符的优先级,再进一步进行组合。例如,`2 + 3 * 5` 首先被看作具有五个元素的列表,即 `2`、`+`、`3`、`*`、`5`,随后根据运算符优先级组合为 `(2 + (3 * 5))`。
|
||||
> 在解析时,一个中缀表达式将作为一个扁平列表表示,然后根据运算符的优先级,再进一步进行组合。例如,`2 + 3 * 5` 首先被看作具有五个元素的列表,即 `2`、`+`、`3`、`*`、`5`,随后根据运算符优先级组合为 `(2 + (3 * 5))`。
|
||||
|
||||
|
||||
#### binary-expression {#binary-expression}
|
||||
> 二元表达式语法
|
||||
#### infix-expression {#infix-expression}
|
||||
> 中置表达式语法
|
||||
>
|
||||
> *二元表达式* → [二元运算符](./02_Lexical_Structure.md#binary-operator) [前缀表达式](#prefix-expression)
|
||||
> *中置表达式* → [中置运算符](./02_Lexical_Structure.md#infix-operator) [前缀表达式](#prefix-expression)
|
||||
>
|
||||
> *二元表达式* → [赋值运算符](#assignment-operator) [try 运算符](#try-operator)<sub>可选</sub> [前缀表达式](#prefix-expression)
|
||||
> *中置表达式* → [赋值运算符](#assignment-operator) [try 运算符](#try-operator)<sub>可选</sub> [前缀表达式](#prefix-expression)
|
||||
>
|
||||
> *二元表达式* → [条件运算符](#conditional-operator) [try 运算符](#try-operator)<sub>可选</sub> [前缀表达式](#prefix-expression)
|
||||
> *中置表达式* → [条件运算符](#conditional-operator) [try 运算符](#try-operator)<sub>可选</sub> [前缀表达式](#prefix-expression)
|
||||
>
|
||||
> *二元表达式* → [类型转换运算符](#type-casting-operator)
|
||||
> *中置表达式* → [类型转换运算符](#type-casting-operator)
|
||||
|
||||
#### binary-expressions {#binary-expressions}
|
||||
> *二元表达式列表* → [二元表达式](#binary-expression) [二元表达式列表](#binary-expressions)<sub>可选</sub>
|
||||
#### infix-expressions {#infix-expressions}
|
||||
> *中置表达式列表* → [中置表达式](#infix-expression) [中置表达式列表](#infix-expressions)<sub>可选</sub>
|
||||
|
||||
### 赋值表达式 {#assignment-operator}
|
||||
赋值表达式会为某个给定的表达式赋值,形式如下;
|
||||
@ -235,7 +235,7 @@ f(x as Any)
|
||||
> *类型转换运算符* → **as** **!** [类型](./03_Types.md#type)
|
||||
|
||||
## 基本表达式 {#primary-expressions}
|
||||
*基本表达式*是最基本的表达式。它们可以单独使用,也可以跟前缀表达式、二元表达式、后缀表达式组合使用。
|
||||
*基本表达式*是最基本的表达式。它们可以单独使用,也可以跟前缀表达式、中置表达式、后缀表达式组合使用。
|
||||
|
||||
> 基本表达式语法
|
||||
|
||||
@ -461,6 +461,16 @@ struct Point {
|
||||
|
||||
闭包的参数声明形式跟函数一样,请参阅 [函数声明](./06_Declarations.md#function-declaration)。
|
||||
|
||||
在闭包表达式中写入 `throws` 或 `async` 将显式地将闭包标记为丢掷或异步的。
|
||||
|
||||
```swift
|
||||
{ (parameters) async throws -> return type in
|
||||
statements
|
||||
}
|
||||
```
|
||||
|
||||
如果闭包的主体中含有 try 表达式,则认为该闭包会引发异常。同理,若闭包主体含有 await 表达式,则认为该闭包是异步的。
|
||||
|
||||
闭包还有几种特殊的形式,能让闭包使用起来更加简洁:
|
||||
|
||||
- 闭包可以省略它的参数和返回值的类型。如果省略了参数名和所有的类型,也要省略 `in` 关键字。如果被省略的类型无法被编译器推断,那么就会导致编译错误。
|
||||
@ -555,11 +565,11 @@ myFunction { [weak parent = self.parent] in print(parent!.title) }
|
||||
>
|
||||
> #### closure-expression {#closure-expression}
|
||||
>
|
||||
> *闭包表达式* → **{** [闭包签名](#closure-signature)<sub>可选</sub> [语句](#statements) **}**
|
||||
> *闭包表达式* → **{** [特性](#attribute)<sub>可选</sub> [闭包签名](#closure-signature)<sub>可选</sub> [语句](#statements) **}**
|
||||
>
|
||||
> #### closure-signature {#closure-signature}
|
||||
>
|
||||
> *闭包签名* → [捕获列表](#capture-list)<sub>可选</sub> [闭包形参子句](#closure-parameter-clause) **throws**<sub>可选</sub> [函数结果](./06_Declarations.md#function-result)<sub>可选</sub> **in**
|
||||
> *闭包签名* → [捕获列表](#capture-list)<sub>可选</sub> [闭包形参子句](#closure-parameter-clause) **async**<sub>可选</sub> **throws**<sub>可选</sub> [函数结果](./06_Declarations.md#function-result)<sub>可选</sub> **in**
|
||||
>
|
||||
> *闭包签名* → [捕获列表](#capture-list) **in**
|
||||
>
|
||||
@ -1255,6 +1265,23 @@ let x = [10, 3, 20, 15, 4]
|
||||
.map { $0 * 100 }
|
||||
```
|
||||
|
||||
你可以将这种多行链式语法与编译器控制语句结合,以控制调用每个方法的时间。例如,以下代码在 iOS 上应用了不同的过滤规则:
|
||||
|
||||
```swift
|
||||
let numbers = [10, 20, 33, 43, 50]
|
||||
#if os(iOS)
|
||||
.filter { $0 < 40}
|
||||
#else
|
||||
.filter {$0 > 25}
|
||||
#endif
|
||||
```
|
||||
|
||||
在 `#if`、`#endif` 和其它编译指令之间的条件编译块可以包含一个隐式成员表达式,后跟零个或多个后缀,以形成一个后缀表达式。这些条件编译块还可以包含另一个条件编译块,或者这些表达式和块的组合体。
|
||||
|
||||
除了顶级代码(top-level code)以外,你还可以在任何能编写显式成员表达式的地方使用上述语法。
|
||||
|
||||
在条件编译块中,编译指令 `#if` 的分支必须包含至少一个表达式,其它分支可以为空。
|
||||
|
||||
> 显式成员表达式语法
|
||||
|
||||
#### explicit-member-expression {#explicit-member-expression}
|
||||
@ -1262,7 +1289,9 @@ let x = [10, 3, 20, 15, 4]
|
||||
>
|
||||
> *显式成员表达式* → [后缀表达式](#postfix-expression) **.** [标识符](./02_Lexical_Structure.md#identifier) [泛型实参子句](./09_Generic_Parameters_and_Arguments.md#generic-argument-clause)<sub>可选</sub><br/>
|
||||
>
|
||||
> *显式成员表达式* → [后缀表达式](#postfix-expression) **.** [标识符](./02_Lexical_Structure.md#identifier) **(** [参数名称](#argument-names) **)**
|
||||
> *显式成员表达式* → [后缀表达式](#postfix-expression) **.** [标识符](./02_Lexical_Structure.md#identifier) **(** [参数名称](#argument-names) **)**
|
||||
|
||||
> *显示成员表达式* → [后缀表达式](#postfix-expression) [条件编译块](#conditional-compilation-block)
|
||||
|
||||
#### argument-names {#argument-names}
|
||||
> *参数名称* → [参数名](#argument-name) [参数名称](#argument-names)<sub>可选</sub><br/>
|
||||
|
@ -105,7 +105,7 @@ while condition {
|
||||
> *case 条件* → **case** [模式](./08_Patterns.md#pattern) [构造器](./06_Declarations.md#initializer)
|
||||
|
||||
#### optional-binding-condition {#optional-binding-condition}
|
||||
> *可选绑定条件* → **let** [模式](./08_Patterns.md#pattern) [构造器](./06_Declarations.md#initializer) | **var** [模式](./08_Patterns.md#pattern) [构造器](./06_Declarations.md#initializer)
|
||||
> *可选绑定条件* → **let** [模式](./08_Patterns.md#pattern) [构造器](./06_Declarations.md#initializer)<sub>可选</sub> | **var** [模式](./08_Patterns.md#pattern) [构造器](./06_Declarations.md#initializer)<sub>可选</sub>
|
||||
|
||||
### Repeat-While 语句 {#repeat-while-statements}
|
||||
`repeat-while` 语句至少执行一次代码块,之后只要循环条件为真,就会重复执行代码块。
|
||||
@ -635,7 +635,7 @@ print("Compiled with the Swift 5 compiler or later in a Swift mode earlier than
|
||||
// 打印 "Compiled with the Swift 5 compiler or later in a Swift mode earlier than 5"
|
||||
```
|
||||
|
||||
`canImport()` 条件传入的实参是模块的名字,这个模块可能并不是每个平台上都存在的。使用它可以检测是否可以导入这个模块,但实际上并没有导入。如果模块存在就返回 `true`,否则返回 `false` 。
|
||||
`canImport()` 条件传入的实参是模块的名字,这个模块可能并不是每个平台上都存在的。该模块的命名可以包含 `.` 符号。使用它可以检测是否可以导入这个模块,但实际上并没有导入。如果模块存在就返回 `true`,否则返回 `false` 。
|
||||
|
||||
`targetEnvironment()` 条件在特殊环境编译时会返回 `true`,否则返回 `false` 。
|
||||
|
||||
@ -663,6 +663,7 @@ statements to compile if both compilation conditions are false
|
||||
>
|
||||
> 即使没有被编译,上面编译配置中的每个语句仍然会被解析。然而,唯一的例外是编译配置语句中包含 `swift()` 或 `compiler()` 条件:这时仅当编译器版本和语言版本匹配时,语句才会被解析。这种设定能确保旧的编译器不会尝试去解析新 Swift 版本的语法。
|
||||
|
||||
关于在条件编译块中如何包装显式成员表达式,请参见 [显式成员表达式](#Expressions.xhtml#ID400) 章节。
|
||||
|
||||
#### build-config-statement {#build-config-statement}
|
||||
> 条件编译代码块语法
|
||||
@ -821,7 +822,8 @@ if #available(platform name version, ..., *) {
|
||||
|
||||
#### availability-condition {#availability-condition}
|
||||
> *可用性条件* → **#available** **(** [可用性参数列表](#availability-arguments) **)**
|
||||
|
||||
>
|
||||
> *可用性条件* → **#unavaliable** **(** [可用性参数列表](#availability-arguments) **)**
|
||||
#### availability-arguments {#availability-arguments}
|
||||
> *可用性参数列表* → [可用性参数](#availability-argument) | [可用性参数](#availability-argument) **,** [可用性参数列表](#availability-arguments)
|
||||
|
||||
|
@ -630,6 +630,10 @@ func 函数名称(参数列表) async -> 返回类型 {
|
||||
|
||||
`async` 关键字是函数类型中的一部分。同步函数是异步函数的子类型。所以,你可以在使用异步函数的地方,使用同步函数。同步方法可以重写异步方法,且同步方法可以满足对异步方法的协议要求。
|
||||
|
||||
你可以根据函数是否异步来重写函数。在调用点,上下文决定了应用哪种函数进行重写:异步上下文使用异步函数;同步上下文使用同步函数。
|
||||
|
||||
异步方法无法重写同步方法,异步方法也无法满足同步方法的协议要求。反过来说,同步方法可以重写异步方法,并且同步方法可以满足异步方法的协议要求。
|
||||
|
||||
### 永不返回的函数 {#functions-that-never-return}
|
||||
Swift 定义了 `Never` 类型,它表示函数或者方法不会返回给它的调用者。`Never` 返回类型的函数或方法可以称为不归,不归函数、方法要么引发不可恢复的错误,要么永远不停地运作,这会使调用后本应执行得代码就不再执行了。但即使是不归函数、方法,抛错函数和重抛出函数也可以将程序控制转移到合适的 `catch` 代码块。
|
||||
|
||||
@ -1307,7 +1311,7 @@ convenience init(参数列表) {
|
||||
> 如果使用 `required` 声明修饰符标记一个构造器,在子类中重写这种构造器时,无需使用 `override` 修饰符。
|
||||
>
|
||||
|
||||
就像函数和方法,构造器也可以抛出或者重抛错误,你可以在构造器参数列表的圆括号之后使用 `throws` 或 `rethrows` 关键字来表明相应的抛出行为。
|
||||
就像函数和方法,构造器也可以抛出或者重抛错误,你可以在构造器参数列表的圆括号之后使用 `throws` 或 `rethrows` 关键字来表明相应的抛出行为。同样,构造器也可以是异步的,你可以使用 `async` 关键字来表明这一点。
|
||||
|
||||
关于在不同类型中声明构造器的例子,请参阅 [构造过程](../02_language_guide/14_Initialization.md)。
|
||||
|
||||
@ -1350,7 +1354,6 @@ if let actualInstance = SomeStruct(input: "Hello") {
|
||||
|
||||
更多关于可失败构造器的信息和例子,请参阅 [可失败构造器](../02_language_guide/14_Initialization.md#failable-initializers)。
|
||||
|
||||
|
||||
#### grammer-of-an-initializer-declaration {#grammer-of-an-initializer-declaration}
|
||||
> 构造器声明语法
|
||||
>
|
||||
|
@ -685,6 +685,12 @@ struct ArrayBuilder {
|
||||
|
||||
编译生成可执行程序的 Swift 代码最多只能拥有一个顶级代码入口,请参阅[顶级代码](../03_language_reference/06_Declarations.md#top-level-code)。
|
||||
|
||||
### `unchecked` {#unchecked}
|
||||
|
||||
该特性用于协议类型,将其作为已采用协议的类型声明列表的一部分,以关闭该协议要求的强制执行。
|
||||
|
||||
仅支持 [Sendable](https://developer.apple.com/documentation/swift/sendable) 协议。
|
||||
|
||||
### `usableFromInline` {#usablefrominline}
|
||||
|
||||
该特性用于函数、方法、计算属性、下标、构造器或析构器的声明,以在同一模块中允许该符号用于内联代码的声明。声明必须具有 `internal` 访问级别修饰符。被标记为 `usableFromInline` 的结构体或类它们属性的类型只能是被标记为 public 或者 `usableFromInline` 的类型。被标记为 `usableFromInline` 的枚举,它 case 的真实值或者关联类型只能是被标记为 public 或者 `usableFromInline` 的类型。
|
||||
@ -733,6 +739,14 @@ Interface Builder 特性是 Interface Builder 用来与 Xcode 同步的声明特
|
||||
|
||||
在函数或者方法声明上使用该特性,它表示参数将不会被存储以供延迟执行。这将确保参数不会超出函数调用的生命周期。在使用 `escaping` 特性声明的函数类型中访问属性和方法时需要显式地使用 `self.`。关于如何使用 `escaping` 特性的例子,请参阅 [逃逸闭包](../02_language_guide/07_Closures.md#escaping-closures)。
|
||||
|
||||
### `Sendable` {#Sendable}
|
||||
|
||||
在函数类型上使用该特性以指示该函数是闭包或可发送的。在函数类型上使用该特性与使非函数类型符合 `Sendable` 协议具有相同的意义。
|
||||
|
||||
当一个函数或闭包被用在需要可发送值的情况,且该函数或闭包满足可发送的要求,则可以在该函数或闭包上推断此特性。
|
||||
|
||||
可发送函数类型是对应的不可发送函数类型的一个子类型。
|
||||
|
||||
## Switch Case 特性 {#switch-case-attributes}
|
||||
|
||||
你只能在 switch cases 语句中使用 switch case 特性。
|
||||
|
@ -7,6 +7,8 @@
|
||||
> *空白字符* → [空白字符项](./02_Lexical_Structure.md#whitespace-item) [空白字符](./02_Lexical_Structure.md#whitespace)<sub>可选</sub>
|
||||
>
|
||||
> *空白字符项* → [换行符](./02_Lexical_Structure.md#line-break)
|
||||
>
|
||||
> *空白字符项* → [内联空间](./02_Lexical_Structure.md#ginline-space)
|
||||
>
|
||||
> *空白字符项* → [注释](./02_Lexical_Structure.md#comment)
|
||||
>
|
||||
@ -108,7 +110,7 @@
|
||||
|
||||
> 字面量语法
|
||||
>
|
||||
> *字面量* → [数值型字面量](./02_Lexical_Structure.md#numeric-literal) | [字符串字面量](./02_Lexical_Structure.md#string-literal) | [布尔字面量](./02_Lexical_Structure.md#boolean-literal) | [空字面量](./02_Lexical_Structure.md#nil-literal)
|
||||
> *字面量* → [数值型字面量](./02_Lexical_Structure.md#numeric-literal) | [字符串字面量](./02_Lexical_Structure.md#string-literal) | [正则表达式字面量](./02_Lexical_Structure.md#regular-expression-literal) | [布尔字面量](./02_Lexical_Structure.md#boolean-literal) | [空字面量](./02_Lexical_Structure.md#nil-literal)
|
||||
>
|
||||
> *数值型字面量* → **-**<sub>可选</sub>[整形字面量](./02_Lexical_Structure.md#integer-literal) | **-**<sub>可选</sub>[浮点型字面量](./02_Lexical_Structure.md#floating-point-literal)
|
||||
>
|
||||
@ -243,6 +245,19 @@
|
||||
>
|
||||
> *转义换行符* → [转义序列](./02_Lexical_Structure.md#escape-sequence) [空白](./02_Lexical_Structure.md#whitespace)<sub>可选</sub> [换行符](./02_Lexical_Structure.md#line-break)
|
||||
|
||||
<!-- -->
|
||||
|
||||
> 正则表达式字面量语法
|
||||
>
|
||||
> *正则表达式字面量* → [正则表达式字面量开分隔定界符](./02_Lexical_Structure.md#regular-expression-literal-opening-delimiter) [正则表达式](./02_Lexical_Structure.md#regular-expression) [正则表达式字面量闭分隔定界符](./02_Lexical_Structure.md#regular-expression-literal-closing-delimiter)
|
||||
>
|
||||
> *正则表达式* → 任何正则表达式
|
||||
>
|
||||
> *正则表达式字面量开分隔定界符* → [正则表达式扩展分隔符](./02_Lexical_Structure.md#grammar_extended-regular-expression-literal-delimiter)<sub>可选</sub> **/**
|
||||
>
|
||||
> *正则表达式字面量闭分割定界符* → **/** [正则表达式扩展分隔符](./02_Lexical_Structure.md#grammar_extended-regular-expression-literal-delimiter)<sub>可选</sub>
|
||||
>
|
||||
> *正则表达式扩展分隔符* → **#** [正则表达式扩展分隔符](./02_Lexical_Structure.md#grammar_extended-regular-expression-literal-delimiter)<sub>可选</sub>
|
||||
|
||||
<!-- -->
|
||||
|
||||
@ -329,11 +344,15 @@
|
||||
>
|
||||
> *类型* → [隐式解析可选类型](./03_Types.md#implicitly-unwrapped-optional-type)
|
||||
>
|
||||
> *类型* → [协议合成类型](./03_Types.md#protocol-composition-type)
|
||||
> *类型* → [协议合成类型](./03_Types.md#protocol-composition-type)
|
||||
>
|
||||
> *类型* → [隐含类型](./03_Types.md#opaque-type)
|
||||
>
|
||||
> *类型* → [元类型](./03_Types.md#metatype-type)
|
||||
>
|
||||
> *类型* → **Any**
|
||||
> *类型* → [任意类型](./03_Types.md#any-type)
|
||||
>
|
||||
> *类型* → **Self**
|
||||
> *类型* → [自身类型](./03_Types.md#self-type)
|
||||
>
|
||||
> *类型* → **(** [type](./03_Types.md#metatype-type) **)**
|
||||
|
||||
@ -368,7 +387,7 @@
|
||||
|
||||
> 函数类型语法
|
||||
>
|
||||
> *函数类型* → [类型](./03_Types.md#type) **throws**<sub>可选</sub>**->** [类型](./03_Types.md#type)
|
||||
> *函数类型* → [类型](./03_Types.md#type) [函数类型子句](.03/Types.md#function-type-argument-clause) **async**<sub>可选</sub> **throws**<sub>可选</sub>**->** [类型](./03_Types.md#type)
|
||||
>
|
||||
> *函数类型* → [类型](./03_Types.md#) **rethrows** **->** [类型](./03_Types.md#)
|
||||
>
|
||||
@ -427,7 +446,7 @@
|
||||
>
|
||||
> *类型继承从句* → **:** [类型继承集](./03_Types.md#type-inheritance-list)
|
||||
>
|
||||
> *类型继承集* → [类型标识符](./03_Types.md#type-identifier) | [类型标识符](./03_Types.md#type-identifier) **,** [类型继承集](./03_Types.md#type-inheritance-list)
|
||||
> *类型继承集* → [特性](./07_Attributes.md#attributes)<sub>可选</sub> [类型标识符](./03_Types.md#type-identifier) | [特性](./07_Attributes.md#attributes)<sub>可选</sub> [类型标识符](./03_Types.md#type-identifier) **,** [类型继承集](./03_Types.md#type-inheritance-list)
|
||||
>
|
||||
> *类条件* → **class**
|
||||
|
||||
@ -460,17 +479,23 @@
|
||||
|
||||
<!-- -->
|
||||
|
||||
> 二元表达式语法
|
||||
> await 表达式语法
|
||||
>
|
||||
> *await 操作符* → **await**
|
||||
|
||||
<!-- -->
|
||||
|
||||
> 中缀表达式语法
|
||||
>
|
||||
> *二元表达式* → [二元运算符](./02_Lexical_Structure.md#binary-operator) [前缀表达式](./04_Expressions.md#prefix-expression)
|
||||
> *中缀表达式* → [中缀运算符](./02_Lexical_Structure.md#infix-operator) [前缀表达式](./04_Expressions.md#prefix-expression)
|
||||
>
|
||||
> *二元表达式* → [赋值操作符](./06_Declarations.md#class-declaration) [try 运算符](./04_Expressions.md#try-operator)<sub>可选</sub> [前缀表达式](./04_Expressions.md#prefix-expression)
|
||||
> *中缀表达式* → [赋值操作符](./06_Declarations.md#class-declaration) [try 运算符](./04_Expressions.md#try-operator)<sub>可选</sub> [前缀表达式](./04_Expressions.md#prefix-expression)
|
||||
>
|
||||
> *二元表达式* → [条件运算符](./04_Expressions.md#conditional-operator) [try 运算符](./04_Expressions.md#try-operator)<sub>可选</sub> [前缀表达式](./04_Expressions.md#prefix-expression)
|
||||
> *中缀表达式* → [条件运算符](./04_Expressions.md#conditional-operator) [try 运算符](./04_Expressions.md#try-operator)<sub>可选</sub> [前缀表达式](./04_Expressions.md#prefix-expression)
|
||||
>
|
||||
> *二元表达式* → [类型转换运算符](./04_Expressions.md#type-casting-operator)
|
||||
> *中缀表达式* → [类型转换运算符](./04_Expressions.md#type-casting-operator)
|
||||
>
|
||||
> *二元表达式* → [二元表达式](./04_Expressions.md#binary-expression) [二元表达式列表](./04_Expressions.md#binary-expressions)<sub>可选</sub>
|
||||
> *中缀表达式* → [中缀表达式](./04_Expressions.md#infix-expression) [中缀表达式列表](./04_Expressions.md#infix-expressions)<sub>可选</sub>
|
||||
>
|
||||
|
||||
<!-- -->
|
||||
@ -588,7 +613,7 @@
|
||||
> *闭包表达式* → **{** [闭包签名](./04_Expressions.md#closure-signature)<sub>可选</sub> [语句](./04_Expressions.md#statements) **}**
|
||||
>
|
||||
>
|
||||
> 闭包签名* → [参数子句](./04_Expressions.md#parameter-clause) [函数结果](./06_Declarations.md#function-result)<sub>可选</sub> **in**
|
||||
> *闭包签名* → [捕获列表](./04_Expressions.md#capture-list) [参数子句](./04_Expressions.md#parameter-clause) **async**<sub>可选</sub> **throws**<sub>可选</sub> [函数结果](./06_Declarations.md#function-result)<sub>可选</sub> **in**
|
||||
>
|
||||
> *闭包签名* → [标识符列表](./04_Expressions.md#identifier-list) [函数结果](./06_Declarations.md#function-result)<sub>可选</sub> **in**
|
||||
>
|
||||
@ -655,7 +680,7 @@
|
||||
> *key-path 组件* → [标识符](./02_Lexical_Structure.md#identifier) [多个 key-path 后缀](./04_Expressions.md#key-path-postfixes)<sub>可选<sub> | [多个 key-path 后缀](./04_Expressions.md#key-path-postfixes)
|
||||
> *多个 key-path 后缀* → [key-path 后缀](./04_Expressions.md#key-path-postfix) [多个 key-path 后缀](./04_Expressions.md#key-path-postfixes)<sub>可选<sub> key-path-postfixes {./04_Expressions.md#key-path-postfixes}
|
||||
>
|
||||
> *key-path 后缀* → **?** | **!** | **self** | **\[** [函数调用参数表](./04_Expressions.md#function-call-argument-list) **\]**
|
||||
> *key-path 后缀* → **?** | **!** | **self** | **[** [函数调用参数表](./04_Expressions.md#function-call-argument-list) **]**
|
||||
>
|
||||
|
||||
|
||||
@ -734,12 +759,14 @@
|
||||
|
||||
> 显式成员表达式语法
|
||||
>
|
||||
> *显式成员表达式* → [后缀表达式](./04_Expressions.md#postfix-expression) **.** [十进制数字] (02_Lexical_Structure.md#decimal-digit)
|
||||
> *显式成员表达式* → [后缀表达式](./04_Expressions.md#postfix-expression) **.** [十进制数字](02_Lexical_Structure.md#decimal-digit)
|
||||
>
|
||||
> *显式成员表达式* → [后缀表达式](./04_Expressions.md#postfix-expression) **.** [标识符](02_Lexical_Structure.md#identifier) [泛型实参子句](./09_Generic_Parameters_and_Arguments.md#generic-argument-clause)<sub>可选</sub><br/>
|
||||
>
|
||||
> *显式成员表达式* → [后缀表达式](./04_Expressions.md#postfix-expression) **.** [标识符] (02_Lexical_Structure.md#identifier) **(** [参数名称](./04_Expressions.md#argument-names) **)**
|
||||
>
|
||||
> *显式成员表达式* → [后缀表达式](./04_Expressions.md#postfix-expression) **.** [标识符](02_Lexical_Structure.md#identifier) **(** [参数名称](./04_Expressions.md#argument-names) **)**
|
||||
>
|
||||
> *显式成员表达式* → [后缀表达式](./04_Expressions.md#postfix-expression) [条件编译块](./05_Statements.md#conditional-compilation-block)
|
||||
>
|
||||
> *参数名称* → [参数名](./04_Expressions.md#argument-name) [参数名称](./04_Expressions.md#argument-names)<sub>可选</sub><br/>
|
||||
>
|
||||
> *参数名* → [标识符](./02_Lexical_Structure.md#identifier) **:**
|
||||
@ -821,12 +848,13 @@
|
||||
>
|
||||
> *while 语句* → **while** [条件集](./05_Statements.md#condition-list) [代码块](./06_Declarations.md#code-block)
|
||||
>
|
||||
> *条件集* → [条件](./05_Statements.md#condition) | [条件](./05_Statements.md#condition) **,** [条件集](./05_Statements.md#condition-list)
|
||||
> *条件集* → [条件](./05_Statements.md#condition) | [条件](./05_Statements.md#condition) **,** [条件集](./05_Statements.md#condition-list)
|
||||
>
|
||||
> *条件* → [表达式](./04_Expressions.md#expression) | [可用性条件](./05_Statements.md#availability-condition) | [case 条件](./05_Statements.md#case-condition) | [可选绑定条件](./05_Statements.md#optional-binding-condition)
|
||||
>
|
||||
> *case 条件* → **case** [模式](./08_Patterns.md#pattern) [构造器](./06_Declarations.md#initializer)
|
||||
>
|
||||
> *可选绑定条件* → **let** [模式](./08_Patterns.md#pattern) [构造器](./06_Declarations.md#initializer) | **var** [模式](./08_Patterns.md#pattern) [构造器](./06_Declarations.md#initializer)
|
||||
> *可选绑定条件* → **let** [模式](./08_Patterns.md#pattern) [构造器](./06_Declarations.md#initializer)<sub>可选</sub> | **var** [模式](./08_Patterns.md#pattern) [构造器](./06_Declarations.md#initializer)<sub>可选</sub>
|
||||
>
|
||||
|
||||
<!-- -->
|
||||
@ -978,7 +1006,7 @@
|
||||
>
|
||||
> *catch 子句集* → [catch 子句](./05_Statements.md#catch-clause) [catch 子句集](05_Statements.md#catch-clauses)<sub>可选</sub>
|
||||
>
|
||||
> *catch 子句* → **catch** [catch 模式列表]()<sub>可选</sub> [代码块](./06_Declarations.md#code-block)<sub>可选</sub>
|
||||
> *catch 子句* → **catch** [catch 模式列表](./05_Statements.md#catch-pattern-list)<sub>可选</sub> [代码块](./06_Declarations.md#code-block)<sub>可选</sub>
|
||||
>
|
||||
> *catch 模式列表* → [catch 模式](./05_Statements.md#catch-pattern) | [catch 模式](./05_Statements.md#catch-pattern) ,[catch 模式列表](./05_Statements.md#catch-pattern-list)
|
||||
>
|
||||
@ -1120,6 +1148,8 @@
|
||||
> *声明* → [结构体声明](./06_Declarations.md#struct-declaration)
|
||||
>
|
||||
> *声明* → [类声明](./06_Declarations.md#class-declaration)
|
||||
>
|
||||
> *声明* → [actor 声明](./06_Declarations.md#actor-declaration)
|
||||
>
|
||||
> *声明* → [协议声明](./06_Declarations.md#protocol-declaration)
|
||||
>
|
||||
@ -1249,10 +1279,10 @@
|
||||
>
|
||||
> *函数名* → [标识符](./02_Lexical_Structure.md#identifier) | [运算符](./02_Lexical_Structure.md#operator)
|
||||
>
|
||||
> *函数签名* → [参数子句](./06_Declarations.md#parameter-clause) **throws**<sub>可选</sub> [函数结果](./06_Declarations.md#function-result)<sub>可选</sub>
|
||||
> *函数签名* → [参数子句](./06_Declarations.md#parameter-clause) **async**<sub>可选</sub> **throws**<sub>可选</sub> [函数结果](./06_Declarations.md#function-result)<sub>可选</sub>
|
||||
>
|
||||
|
||||
> *函数签名* → [参数子句](./06_Declarations.md#parameter-clause) **rethrows** [函数结果](./06_Declarations.md#function-result)<sub>可选</sub>
|
||||
> *函数签名* → [参数子句](./06_Declarations.md#parameter-clause) **async**<sub>可选</sub> **rethrows** [函数结果](./06_Declarations.md#function-result)<sub>可选</sub>
|
||||
>
|
||||
> *函数结果* → **->** [特性](./07_Attributes.md#attributes)<sub>可选</sub> [类型](./03_Types.md#type)
|
||||
>
|
||||
@ -1516,6 +1546,8 @@
|
||||
> *声明修饰符* → [访问级别修饰符](./07_Attributes.md#access-level-modifier)
|
||||
>
|
||||
> *声明修饰符* → [可变性修饰符](./07_Attributes.md#mutation-modifier)
|
||||
>
|
||||
> *声明修饰符* → [actor 隔离修饰符](./06_Deeclarations.md#actor-isolation-modifier)
|
||||
>
|
||||
> *声明修饰符集* → [声明修饰符](./06_Declarations.md#declaration-modifier) [声明修饰符集](./06_Declarations.md#declaration-modifiers)<sub>可选</sub>
|
||||
>
|
||||
@ -1531,6 +1563,8 @@
|
||||
>
|
||||
> *可变性修饰符* → **mutating** | **nonmutating**
|
||||
>
|
||||
> *actor 隔离修饰符* → **nonisolated**
|
||||
>
|
||||
|
||||
## 属性 {#attributes}
|
||||
|
||||
|
@ -1,5 +1,18 @@
|
||||
# Swift 文档修订历史
|
||||
|
||||
### 2022-06-06
|
||||
|
||||
* 更新至 Swift 5.7。
|
||||
* 新增 [可发送类型](../02_language_guide/28_Concurrency.md#Sendable-Types) 章节,其中包含在 actors 和任务间发送数据的内容。在 [可发送](03_language_reference/07_Attributes.md#Sendable) 章节和 [unchecked](03_language_reference/07_Attributes.md#unchecked) 章节新增了有关特性 `@Sendable` 和 `@unchecked` 的内容。
|
||||
* 新增了 [正则表达式字面量](03_language_reference/02_Lexical_Structure.md#regular-expression-literals) 章节,其中包含新建正则表达式的内容。
|
||||
* 在 [可选绑定](../02_language_guide/01_The_Basics.md#optional-binding) 章节新增了 `if-let` 结构更简短的一种形式。
|
||||
* 在 [检查 API 可用性](../02_language_guide/05_Control_Flow.md#checking-api-availability) 章节新增了与不可用性检查 `#unavaliable` 有关的内容。
|
||||
|
||||
### 2022-03-14
|
||||
|
||||
* 更新至 Swift 5.6
|
||||
* 更新了 [显式成员表达式](../03_language_reference/04_Expressions.md#explicit-member-expression) 章节,现在可以在链式调用方法和其它后缀表达式周围使用 `#if` 了。
|
||||
|
||||
### 2021-07-14
|
||||
|
||||
* 更新 [并发](../02_language_guide/28_Concurrency.md) 篇章里的示例,使用当前的并发 API。
|
||||
|
Reference in New Issue
Block a user