From ed0b278e73c973bb5becb11b2bb5930a190459c9 Mon Sep 17 00:00:00 2001 From: king-open Date: Thu, 26 Sep 2024 15:38:48 +0800 Subject: [PATCH 01/14] =?UTF-8?q?=E7=BF=BB=E8=AF=91=E5=AE=8C1342=20Pattern?= =?UTF-8?q?s.md?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- swift-6-beta.docc/ReferenceManual/Patterns.md | 197 +++++------------- 1 file changed, 52 insertions(+), 145 deletions(-) diff --git a/swift-6-beta.docc/ReferenceManual/Patterns.md b/swift-6-beta.docc/ReferenceManual/Patterns.md index 07dced067..af852e87b 100644 --- a/swift-6-beta.docc/ReferenceManual/Patterns.md +++ b/swift-6-beta.docc/ReferenceManual/Patterns.md @@ -1,37 +1,16 @@ -# Patterns - -Match and destructure values. - -A *pattern* represents the structure of a single value -or a composite value. -For example, the structure of a tuple `(1, 2)` is a comma-separated list of two -elements. Because patterns represent the structure of a value rather than any -one particular value, you can match them with a variety of values. -For instance, the pattern `(x, y)` matches the tuple `(1, 2)` and any other -two-element tuple. In addition to matching a pattern with a value, -you can extract part or all of a composite value and bind each part -to a constant or variable name. - -In Swift, there are two basic kinds of patterns: -those that successfully match any kind of value, -and those that may fail to match a specified value at runtime. - -The first kind of pattern is used for destructuring values -in simple variable, constant, and optional bindings. -These include wildcard patterns, identifier patterns, -and any value binding or tuple patterns containing -them. You can specify a type annotation for these patterns -to constrain them to match only values of a certain type. - -The second kind of pattern is used for full pattern matching, -where the values you're trying to match against may not be there at runtime. -These include enumeration case patterns, optional patterns, expression patterns, -and type-casting patterns. You use these patterns in a case label of a `switch` -statement, a `catch` clause of a `do` statement, -or in the case condition of an `if`, `while`, -`guard`, or `for`-`in` statement. - -> Grammar of a pattern: +# 图案 + +匹配和解构值. + +*模式* 表示单个值或复合值的结构。例如,元组`(1, 2)` 的结构是两个元素的逗号分隔列表。由于模式代表值的结构而不是任何一个特定值,因此您可以将它们与多种值进行匹配。例如,模式 `(x, y)`与元组 `(1, 2)` 和任何其他二元素元组匹配。除了将模式与值进行匹配之外,您还可以提取复合值的部分或全部并将每个部分绑定到常量或变量名称。 + +在 Swift 中,有两种基本类型的模式:那些成功匹配任何类型值的模式,以及那些在运行时可能无法匹配指定值的模式。 + +第一种模式用于解构简单变量、常量和可选绑定中的值。其中包括通配符模式、标识符模式以及包含它们的任何值绑定或元组模式。您可以为这些模式指定类型注释,以限制它们仅匹配特定类型的值。 + +第二种模式用于完整模式匹配,其中您尝试匹配的值在运行时可能不存在。其中包括枚举案例模式、可选模式、表达式模式和类型转换模式。您可以在 `switch` 语句的 case 标签、 `do` 语句的 `catch`子句或 `if` 、 `while` 、 `guard` 或 `for` - `in` 语句的 case 条件中使用这些模式。 + +> 模式语法: > > *pattern* → *wildcard-pattern* *type-annotation*_?_ \ > *pattern* → *identifier-pattern* *type-annotation*_?_ \ @@ -42,12 +21,9 @@ or in the case condition of an `if`, `while`, > *pattern* → *type-casting-pattern* \ > *pattern* → *expression-pattern* -## Wildcard Pattern +## 通配符模式 -A *wildcard pattern* matches and ignores any value and consists of an underscore -(`_`). Use a wildcard pattern when you don't care about the values being -matched against. For example, the following code iterates through the closed range `1...3`, -ignoring the current value of the range on each iteration of the loop: +*通配符模式* 匹配并忽略任何值,并由下划线(`_`) 组成. 当您不关心要匹配的值时,请使用通配符模式。例如,以下代码迭代封闭范围 `1...3`,忽略循环每次迭代中范围的当前值: ```swift for _ in 1...3 { @@ -65,16 +41,13 @@ for _ in 1...3 { ``` --> -> Grammar of a wildcard pattern: +> 通配符模式的语法: > > *wildcard-pattern* → **`_`** -## Identifier Pattern +## 标识符模式 -An *identifier pattern* matches any value and binds the matched value to a -variable or constant name. -For example, in the following constant declaration, `someValue` is an identifier pattern -that matches the value `42` of type `Int`: +*标识符模式* 匹配任何值并将匹配的值绑定到变量或常量名称.例如,在以下常量声明中`someValue` 是与 `Int` 类型的值 `42` 匹配的标识符模式: ```swift let someValue = 42 @@ -88,28 +61,19 @@ let someValue = 42 ``` --> -When the match succeeds, the value `42` is bound (assigned) -to the constant name `someValue`. +当匹配成功时,值 `42` 被绑定(分配)到常量名称 `someValue` . -When the pattern on the left-hand side of a variable or constant declaration -is an identifier pattern, -the identifier pattern is implicitly a subpattern of a value-binding pattern. +当变量或常量声明左侧的模式是标识符模式时,标识符模式隐式是值绑定模式的子模式. -> Grammar of an identifier pattern: +> 标识符模式的语法: > > *identifier-pattern* → *identifier* -## Value-Binding Pattern +## 价值绑定模式 -A *value-binding pattern* binds matched values to variable or constant names. -Value-binding patterns that bind a matched value to the name of a constant -begin with the `let` keyword; those that bind to the name of variable -begin with the `var` keyword. +*值绑定模式* 将匹配的值绑定到变量或常量名称。将匹配值绑定到常量名称的值绑定模式以 `let` 关键字开头;那些绑定到变量名称的变量以`var`关键字开头. -Identifiers patterns within a value-binding pattern -bind new named variables or constants to their matching values. For example, -you can decompose the elements of a tuple and bind the value of each element to a -corresponding identifier pattern. +值绑定模式中的标识符模式将新的命名变量或常量绑定到其匹配值。例如,您可以分解元组的元素并将每个元素的值绑定到相应的标识符模式 ```swift let point = (3, 2) @@ -135,11 +99,9 @@ case let (x, y): ``` --> -In the example above, `let` distributes to each identifier pattern in the -tuple pattern `(x, y)`. Because of this behavior, the `switch` cases -`case let (x, y):` and `case (let x, let y):` match the same values. +在上面的示例中, `let` 分配给元组模式`(x, y)` 中的每个标识符模式。由于此行为, `switch` case `case let (x, y):` 和`case (let x, let y):` 匹配相同的值 -> Grammar of a value-binding pattern: +> 值绑定模式的语法: > > *value-binding-pattern* → **`var`** *pattern* | **`let`** *pattern* @@ -151,23 +113,13 @@ tuple pattern `(x, y)`. Because of this behavior, the `switch` cases "Variable pattern" is ambiguous between those two meanings. --> -## Tuple Pattern +## 元组模式 -A *tuple pattern* is a comma-separated list of zero or more patterns, enclosed in -parentheses. Tuple patterns match values of corresponding tuple types. +*元组模式* 是零个或多个模式的逗号分隔列表,括在括号中。元组模式匹配相应元组类型的值 -You can constrain a tuple pattern to match certain kinds of tuple types -by using type annotations. -For example, the tuple pattern `(x, y): (Int, Int)` in the constant declaration -`let (x, y): (Int, Int) = (1, 2)` matches only tuple types in which -both elements are of type `Int`. +您可以使用类型注释来约束元组模式以匹配某些类型的元组类型。例如,常量声明中的元组模式`(x, y): (Int, Int)` `let (x, y): (Int, Int) = (1, 2)` 仅匹配两个元素均为 `Int` 类型的元组类型`. -When a tuple pattern is used as the pattern in a `for`-`in` statement -or in a variable or constant declaration, it can contain only wildcard patterns, -identifier patterns, optional patterns, or other tuple patterns that contain those. -For example, -the following code isn't valid because the element `0` in the tuple pattern `(x, 0)` is -an expression pattern: +当元组模式用作 `for` - `in` 语句或变量或常量声明中的模式时,它只能包含通配符模式、标识符模式、可选模式或包含这些模式的其他元组模式。例如,以下代码无效,因为元组模式 `(x, 0)` 中的元素0是表达式模式: ```swift let points = [(0, 0), (1, 0), (1, 1), (2, 0), (2, 1)] @@ -193,9 +145,7 @@ for (x, 0) in points { ``` --> -The parentheses around a tuple pattern that contains a single element have no effect. -The pattern matches values of that single element's type. For example, the following are -equivalent: +包含单个元素的元组模式周围的括号不起作用。该模式与该单个元素类型的值相匹配。例如,以下内容是等效的: -The optional pattern provides a convenient way to -iterate over an array of optional values in a `for`-`in` statement, -executing the body of the loop only for non-`nil` elements. +可选模式提供了一种方便的方法来迭代 `for` - `in`语句中的可选值数组,仅对非 `nil` 元素执行循环体 ```swift let arrayOfOptionalInts: [Int?] = [nil, 2, 3, nil, 5] @@ -371,31 +301,20 @@ for case let number? in arrayOfOptionalInts { > > *optional-pattern* → *identifier-pattern* **`?`** -## Type-Casting Patterns +## 类型转换模式 -There are two type-casting patterns, the `is` pattern and the `as` pattern. -The `is` pattern appears only in `switch` statement -case labels. The `is` and `as` patterns have the following form: +有两种类型转换模式: `is` 模式和`as` 模式。 `is` 模式仅出现在`switch` 语句 case 标签中. `is` 和 `as` 模式具有以下形式: ```swift is <#type#> <#pattern#> as <#type#> ``` -The `is` pattern matches a value if the type of that value at runtime is the same as -the type specified in the right-hand side of the `is` pattern --- or a subclass of that type. -The `is` pattern behaves like the `is` operator in that they both perform a type cast -but discard the returned type. +如果运行时值的 `is` 与 `is` 模式与该值匹配 - 或者该类型的子类。 `is` 模式的行为类似于 `is` 运算符,因为它们都执行类型转换但丢弃返回的类型。 -The `as` pattern matches a value if the type of that value at runtime is the same as -the type specified in the right-hand side of the `as` pattern --- or a subclass of that type. -If the match succeeds, -the type of the matched value is cast to the *pattern* specified in the right-hand side -of the `as` pattern. +如果运行时该值的类型与`as模` 式右侧指定的类型相同,则 `as` 模式与该值匹配 - 或者该类型的子类。如果匹配成功,则匹配值的类型将转换为 `as` 模式右侧指定的模式 -For an example that uses a `switch` statement -to match values with `is` and `as` patterns, -see . +有关使用 `switch` 语句将值与 `is` 和 `as` 模式进行匹配的示例,请参阅 . > Grammar of a type casting pattern: > @@ -403,21 +322,11 @@ see . > *is-pattern* → **`is`** *type* \ > *as-pattern* → *pattern* **`as`** *type* -## Expression Pattern +## 表达模式 -An *expression pattern* represents the value of an expression. -Expression patterns appear only in `switch` statement -case labels. +*表达式模式* 表示表达式的值。表达式模式仅出现在*switch* 语句 *case* 标签中 -The expression represented by the expression pattern -is compared with the value of an input expression -using the pattern-matching operator (`~=`) from the Swift standard library. -The matches succeeds -if the `~=` operator returns `true`. By default, the `~=` operator compares -two values of the same type using the `==` operator. -It can also match a value with a range of values, -by checking whether the value is contained within the range, -as the following example shows. +使用 Swift 标准库中的模式匹配运算符 ( `~=` ) 将表达式模式表示的表达式与输入表达式的值进行比较。如果`~=` 运算符返回`true` 则匹配成功。默认情况下, `~= ` 运算符使用`==`运算符比较相同类型的两个值。它还可以通过检查值是否包含在范围内来将值与值范围匹配,如以下示例所示。 ```swift let point = (1, 2) @@ -449,9 +358,7 @@ default: ``` --> -You can overload the `~=` operator to provide custom expression matching behavior. -For example, you can rewrite the above example to compare the `point` expression -with a string representations of points. +您可以重载`~=` 运算符以提供自定义表达式匹配行为。例如,您可以重写上面的示例,以将`point`表达式与点的字符串表示形式进行比较. ```swift // Overload the ~= operator to match a string with an integer. @@ -485,15 +392,15 @@ default: ``` --> -> Grammar of an expression pattern: +> 表达式模式的语法: > > *expression-pattern* → *expression* -> Beta Software: +> 测试版软件: > -> This documentation contains preliminary information about an API or technology in development. This information is subject to change, and software implemented according to this documentation should be tested with final operating system software. +> 本文档包含有关正在开发的 API 或技术的初步信息。该信息可能会发生变化,并且根据本文档实现的软件应使用最终操作系统软件进行测试. > -> Learn more about using [Apple's beta software](https://developer.apple.com/support/beta-software/). +> 了解有关使用 [Apple 测试软件的](https://developer.apple.com/support/beta-software/)更多信息. -A `try` expression can't appear on the right-hand side of an infix operator, -unless the infix operator is the assignment operator -or the `try` expression is enclosed in parentheses. +`try`表达式不能出现在中缀运算符的右侧, +除非中缀运算符是赋值运算符, +或者`try`表达式被括在括号内 + -If an expression includes both the `try` and `await` operator, -the `try` operator must appear first. +如果一个表达式同时包含`try`和`await`操作符, +则`try`操作符必须出现在前面。 + -For more information and to see examples of how to use `try`, `try?`, and `try!`, -see . +欲了解更多信息,并查看如何使用`try`、`try?`和`try!`的示例, +请参阅 . -> Grammar of a try expression: +> 尝试表达的语法: > > *try-operator* → **`try`** | **`try`** **`?`** | **`try`** **`!`** -### Await Operator +### 等待操作员 -An *await expression* consists of the `await` operator -followed by an expression that uses the result of an asynchronous operation. -It has the following form: +*等待表达式*由`await`操作符 +后跟使用异步操作结果的表达式组成. +其形式如下: ```swift await <#expression#> ``` +带有`await`的表达式称为*潜在暂停点*。 +异步函数的执行可以暂停 +在每个带有`await`的表达式。 +此外, +并发代码的执行永远不会暂停在任何其他点。 +这意味着潜在暂停点之间的代码 +可以安全地更新需要暂时打破不变量的状态, +前提是它完成更新 +在下一个潜在暂停点之前。 -The value of an `await` expression is the value of the *expression*. - -An expression marked with `await` is called a *potential suspension point*. -Execution of an asynchronous function can be suspended -at each expression that's marked with `await`. -In addition, -execution of concurrent code is never suspended at any other point. -This means code between potential suspension points -can safely update state that requires temporarily breaking invariants, -provided that it completes the update -before the next potential suspension point. - -An `await` expression can appear only within an asynchronous context, -such as the trailing closure passed to the `async(priority:operation:)` function. -It can't appear in the body of a `defer` statement, -or in an autoclosure of synchronous function type. +`await` 表达式只能出现在异步上下文中, +例如传递给 `async(priority:operation:)` 函数的尾部闭包。 +它不能出现在 `defer` 语句的体内, +也不能出现在同步函数类型的自动闭包中。 -When the expression on the left-hand side of an infix operator -is marked with the `await` operator, -that operator applies to the whole infix expression. -That said, you can use parentheses -to be explicit about the scope of the operator's application. +当中缀运算符左侧的表达式 +带有`await`运算符时, +该运算符将应用于整个中缀表达式。 +也就是说,你可以使用括号 +来明确运算符的应用范围。 ```swift // await applies to both function calls @@ -253,9 +247,9 @@ sum = (await someAsyncFunction()) + anotherAsyncFunction() ``` --> -An `await` expression can't appear on the right-hand side of an infix operator, -unless the infix operator is the assignment operator -or the `await` expression is enclosed in parentheses. +`await`表达式不能出现在中缀运算符的右侧, +除非中缀运算符是赋值运算符, +或者”等待"表达式被括在括号内。 -If an expression includes both the `await` and `try` operator, -the `try` operator must appear first. +如果一个表达式同时包含`await`和`try`操作符, +则`try`操作符必须放在前面. -> Grammar of an await expression: +> 等待表达的语法: > > *await-operator* → **`await`** -## Infix Expressions +## 中间词表达 -*Infix expressions* combine -an infix binary operator with the expression that it takes -as its left- and right-hand arguments. -It has the following form: +*中缀表达式*将 +中缀二元运算符与其 +作为左右参数的表达式结合在一起。 +其形式如下: ```swift <#left-hand argument#> <#operator#> <#right-hand argument#> ``` -For information about the behavior of these operators, -see and . +关于这些运营商的行为, +请参阅 . -For information about the operators provided by the Swift standard library, -see [Operator Declarations](https://developer.apple.com/documentation/swift/operator_declarations). +有关Swift标准库提供的操作符的信息, +请参阅 [Operator Declarations](https://developer.apple.com/documentation/swift/operator_declarations). -> Note: At parse time, -> an expression made up of infix operators is represented -> as a flat list. -> This list is transformed into a tree -> by applying operator precedence. -> For example, the expression `2 + 3 * 5` -> is initially understood as a flat list of five items, -> `2`, `+`, `3`, `*`, and `5`. -> This process transforms it into the tree (2 + (3 * 5)). +> 备注:解析时, +> 由中缀运算符组成的表达式用 +> 作为一张平面列表. +> 这个列表会变成一棵树 +> 通过应用运算符优先级. +> 例如,表达 `2 + 3 * 5` +> 最初被理解为五个项目的列表, +> `2`, `+`, `3`, `*`, 和 `5`. +> 这个过程将树木转化成 (2 + (3 * 5)). -> Grammar of an infix expression: +> 中缀表达的语法: > > *infix-expression* → *infix-operator* *prefix-expression* \ > *infix-expression* → *assignment-operator* *try-operator*_?_ *await-operator*_?_ *prefix-expression* \ @@ -331,25 +325,25 @@ see [Operator Declarations](https://developer.apple.com/documentation/swift/oper > *infix-expression* → *type-casting-operator* \ > *infix-expressions* → *infix-expression* *infix-expressions*_?_ -### Assignment Operator +### 作业员 -The *assignment operator* sets a new value -for a given expression. -It has the following form: +*赋值运算符*为给定的表达式设置新的值。 + +其形式如下: ```swift <#expression#> = <#value#> ``` -The value of the *expression* -is set to the value obtained by evaluating the *value*. -If the *expression* is a tuple, -the *value* must be a tuple -with the same number of elements. -(Nested tuples are allowed.) -Assignment is performed from each part of the *value* -to the corresponding part of the *expression*. -For example: +*表达式*的值 +由计算*值*得到的值确定。 +如果*表达式*是一个元组, +*value*必须是一个 +元素数量相同的元组 +(允许嵌套元组)。 +赋值从*value*的每个部分 +到*表达式*的对应部分。 +例如: ```swift (a, _, (b, c)) = ("test", 9.45, (12, 3)) @@ -367,45 +361,45 @@ For example: ``` --> -The assignment operator doesn't return any value. +赋值运算符不返回任何值. -> Grammar of an assignment operator: +> 赋值运算符的语法: > > *assignment-operator* → **`=`** -### Ternary Conditional Operator +### 三元条件运算符 -The *ternary conditional operator* evaluates to one of two given values -based on the value of a condition. -It has the following form: +*三元条件运算符* 根据条件值 +计算两个给定值之一。 +其形式如下: ```swift <#condition#> ? <#expression used if true#> : <#expression used if false#> ``` -If the *condition* evaluates to `true`, -the conditional operator evaluates the first expression -and returns its value. -Otherwise, it evaluates the second expression -and returns its value. -The unused expression isn't evaluated. +如果*条件*的值为`true`, +则条件运算符将计算第一个表达式 +并返回其值。 +否则,它将计算第二个表达式 +并返回其值。 +未使用的表达式将不进行计算 For an example that uses the ternary conditional operator, see . -> Grammar of a conditional operator: +> 条件运算符的语法: > > *conditional-operator* → **`?`** *expression* **`:`** -### Type-Casting Operators +### 类型铸造操作员 -There are four type-casting operators: -the `is` operator, -the `as` operator, -the `as?` operator, -and the `as!` operator. +有四种类型转换操作符: +`is`操作符、 +`as`操作符、 +`as?`操作符、 +以及`as!`操作符 -They have the following form: +它们具有以下形式: ```swift <#expression#> is <#type#> @@ -414,10 +408,10 @@ They have the following form: <#expression#> as! <#type#> ``` -The `is` operator checks at runtime whether the *expression* -can be cast to the specified *type*. -It returns `true` if the *expression* can be cast to the specified *type*; -otherwise, it returns `false`. +`is`运算符在运行时检查*表达式* +是否可以转换为指定的*类型*。 +如果*表达式*可以转换为指定的*类型*,则返回`true`; +否则返回`false`. -The `as` operator performs a cast -when it's known at compile time -that the cast always succeeds, -such as upcasting or bridging. -Upcasting lets you use an expression as an instance of its type's supertype, -without using an intermediate variable. -The following approaches are equivalent: +当在编译时 +已知转换总是成功时, +`as` 运算符执行转换, +例如上转换或桥接。 +上转换允许您将表达式用作其类型超类型的实例, +而无需使用中间变量。 +以下方法等效: ```swift func f(_ any: Any) { print("Function for Any") } @@ -492,49 +486,49 @@ f(x as Any) ``` --> -Bridging lets you use an expression of -a Swift standard library type such as `String` -as its corresponding Foundation type such as `NSString` -without needing to create a new instance. -For more information on bridging, -see [Working with Foundation Types](https://developer.apple.com/documentation/swift/imported_c_and_objective_c_apis/working_with_foundation_types). - -The `as?` operator -performs a conditional cast of the *expression* -to the specified *type*. -The `as?` operator returns an optional of the specified *type*. -At runtime, if the cast succeeds, -the value of *expression* is wrapped in an optional and returned; -otherwise, the value returned is `nil`. -If casting to the specified *type* -is guaranteed to fail or is guaranteed to succeed, -a compile-time error is raised. - -The `as!` operator performs a forced cast of the *expression* to the specified *type*. -The `as!` operator returns a value of the specified *type*, not an optional type. -If the cast fails, a runtime error is raised. -The behavior of `x as! T` is the same as the behavior of `(x as? T)!`. - -For more information about type casting -and to see examples that use the type-casting operators, -see . - -> Grammar of a type-casting operator: +桥接功能允许您将Swift标准库类型 +(如String) +作为其对应的Foundation类型(如NSString) +使用,而无需创建新实例。 +有关桥接的更多信息, +请参阅[Working with Foundation Types](https://developer.apple.com/documentation/swift/imported_c_and_objective_c_apis/working_with_foundation_types). + +`as?` 运算符 +将 *表达式* +转换为指定的 *类型*。 +`as?` 运算符返回指定 *类型* 的可选值。 +在运行时,如果转换成功, +*表达式* 的值将被封装为可选值并返回; +否则,返回的值为 `nil`。 +如果转换为指定的 *类型* +保证失败或保证成功, +将引发编译时错误。 + +`as!` 运算符强制将 *expression* 转换为指定的 *type*。 +`as!` 运算符返回指定 *type* 的值,而非可选类型。 +如果转换失败,将引发运行时错误。 +`x as! T` 的行为与 `(x as? T)!` 的行为相同。 + +如需了解有关类型转换的更多信息 +并查看使用类型转换运算符的示例, +请参阅. + +> 类型转换运算符的语法: > > *type-casting-operator* → **`is`** *type* \ > *type-casting-operator* → **`as`** *type* \ > *type-casting-operator* → **`as`** **`?`** *type* \ > *type-casting-operator* → **`as`** **`!`** *type* -## Primary Expressions +## 主要表达方式 -*Primary expressions* -are the most basic kind of expression. -They can be used as expressions on their own, -and they can be combined with other tokens -to make prefix expressions, infix expressions, and postfix expressions. +*基本表达式* +是最基本的表达式。 +它们可以单独使用, +也可以与其他标记结合, +构成前缀表达式、中缀表达式和后缀表达式。 -> Grammar of a primary expression: +> 初级表达语法: > > *primary-expression* → *identifier* *generic-argument-clause*_?_ \ > *primary-expression* → *literal-expression* \ @@ -564,12 +558,12 @@ to make prefix expressions, infix expressions, and postfix expressions. is a *type* identifier. --> -### Literal Expression +### 字面表达 -A *literal expression* consists of -either an ordinary literal (such as a string or a number), -an array or dictionary literal, -or a playground literal. +一个*字面表达式*由 +普通字面(如字符串或数字)、 +数组或字典字面、 +或游戏字面. > Note: > Prior to Swift 5.9, @@ -601,21 +595,21 @@ or a playground literal. ``` --> -An *array literal* is -an ordered collection of values. -It has the following form: +*数组字面量*是 +有序的数值集合。 +它具有以下形式: ```swift [<#value 1#>, <#value 2#>, <#...#>] ``` -The last expression in the array can be followed by an optional comma. -The value of an array literal has type `[T]`, -where `T` is the type of the expressions inside it. -If there are expressions of multiple types, -`T` is their closest common supertype. -Empty array literals are written using an empty -pair of square brackets and can be used to create an empty array of a specified type. +数组中的最后一个表达式后面可以跟一个可选的逗号。 +数组字面值的类型为`[T]`, +其中`T`是数组中表达式的类型。 +如果有多种类型的表达式, +`T`是它们最接近的公共超类型。 +空数组字面值用一对空 +方括号表示,可用于创建指定类型的空数组. ```swift var emptyArray: [Double] = [] @@ -629,26 +623,26 @@ var emptyArray: [Double] = [] ``` --> -A *dictionary literal* is -an unordered collection of key-value pairs. -It has the following form: +*字典字面意思*是 +一个无序的键值对集合。 +它具有以下形式: ```swift [<#key 1#>: <#value 1#>, <#key 2#>: <#value 2#>, <#...#>] ``` -The last expression in the dictionary can be followed by an optional comma. -The value of a dictionary literal has type `[Key: Value]`, -where `Key` is the type of its key expressions -and `Value` is the type of its value expressions. -If there are expressions of multiple types, -`Key` and `Value` are the closest common supertype -for their respective values. -An empty dictionary literal is written as -a colon inside a pair of brackets (`[:]`) -to distinguish it from an empty array literal. -You can use an empty dictionary literal to create an empty dictionary literal -of specified key and value types. +字典中的最后一个表达式后面可以跟一个可选的逗号。 +字典字面值的类型为[键:值], +其中键是其键表达式的类型, +值是其值表达式的类型。 +如果有多种类型的表达式, +键和值是各自值的最接近的公共超类型。 + +空字典字面值用 +,放在一对括号(`[:]`)内, +以区别于空数组字面量。 +您可以使用空字典字面量创建 +具有指定键和值类型的. ```swift var emptyDictionary: [String: Double] = [:] @@ -662,17 +656,17 @@ var emptyDictionary: [String: Double] = [:] ``` --> -A *playground literal* -is used by Xcode to create an interactive representation -of a color, file, or image within the program editor. -Playground literals in plain text outside of Xcode -are represented using a special literal syntax. +Xcode使用*playground literal* +在程序编辑器中创建 +颜色、文件或图像的交互式表示。 +Xcode之外的纯文本playground literal +使用特殊的文字语法表示。 -For information on using playground literals in Xcode, -see [Add a color, file, or image literal](https://help.apple.com/xcode/mac/current/#/dev4c60242fc) -in Xcode Help. +有关在Xcode中使用playground literal的信息, +请参阅[Add a color, file, or image literal](https://help.apple.com/xcode/mac/current/#/dev4c60242fc) +在Xcode帮助中 -> Grammar of a literal expression: +> 字面表达的语法: > > *literal-expression* → *literal* \ > *literal-expression* → *array-literal* | *dictionary-literal* | *playground-literal* @@ -689,11 +683,11 @@ in Xcode Help. > *playground-literal* → **`#fileLiteral`** **`(`** **`resourceName`** **`:`** *expression* **`)`** \ > *playground-literal* → **`#imageLiteral`** **`(`** **`resourceName`** **`:`** *expression* **`)`** -### Self Expression +### 自我表达 -The `self` expression is an explicit reference to the current type -or instance of the type in which it occurs. -It has the following forms: +`self` 表达是指对当前类型 +或类型实例的明确引用。 +它有以下几种形式: ```swift self @@ -707,15 +701,16 @@ self.init(<#initializer arguments#>) TODO: Come back and explain the second to last form (i.e., self(arg: value)). --> -In an initializer, subscript, or instance method, `self` refers to the current -instance of the type in which it occurs. In a type method, -`self` refers to the current type in which it occurs. +在初始化器、下标或实例方法中,`self` 指的是当前 +出现的类型实例。在类型方法中, +`self` 指的是当前出现的类型。 -The `self` expression is used to specify scope when accessing members, -providing disambiguation when there's -another variable of the same name in scope, -such as a function parameter. -For example: +`self` 表达式用于在访问成员时指定作用域, +当作用域中存在 +另一个同名变量时, +例如函数参数, +提供消除歧义的功能。 +例如: ```swift class SomeClass { @@ -739,9 +734,9 @@ class SomeClass { ``` --> -In a mutating method of a value type, -you can assign a new instance of that value type to `self`. -For example: +在值类型的变体方法中, +您可以将值类型的新实例赋值给`self`。 +例如: ```swift struct Point { @@ -771,7 +766,7 @@ struct Point { -> Grammar of a self expression: +> 自我表达的语法: > > *self-expression* → **`self`** | *self-method-expression* | *self-subscript-expression* | *self-initializer-expression* > @@ -779,11 +774,11 @@ struct Point { > *self-subscript-expression* → **`self`** **`[`** *function-call-argument-list* **`]`** \ > *self-initializer-expression* → **`self`** **`.`** **`init`** -### Superclass Expression +### 超级表达 -A *superclass expression* lets a class -interact with its superclass. -It has one of the following forms: +*超类表达式*允许类 +与其超类进行交互。 +它有以下几种形式: ```swift super.<#member name#> @@ -791,15 +786,14 @@ super[<#subscript index#>] super.init(<#initializer arguments#>) ``` -The first form is used to access a member of the superclass. -The second form is used to access the superclass's subscript implementation. -The third form is used to access an initializer of the superclass. +第一种形式用于访问超类的成员。 +第二种形式用于访问超类的下标实现。 +第三种形式用于访问超类的初始化器。 -Subclasses can use a superclass expression -in their implementation of members, subscripting, and initializers -to make use of the implementation in their superclass. +子类可以在成员、下标和初始化器的实现中使用超类表达式, +以利用其超类的实现. -> Grammar of a superclass expression: +> 超级表达的语法: > > *superclass-expression* → *superclass-method-expression* | *superclass-subscript-expression* | *superclass-initializer-expression* > @@ -807,11 +801,11 @@ to make use of the implementation in their superclass. > *superclass-subscript-expression* → **`super`** **`[`** *function-call-argument-list* **`]`** \ > *superclass-initializer-expression* → **`super`** **`.`** **`init`** -### Conditional Expression +### 条件表达式 + +一个*条件表达式*根据条件值计算出几个给定值中的一个. -A *conditional expression* evaluates to one of several given values -based on the value of a condition. -It has one the following forms: +它有以下几种形式: ```swift if <#condition 1#> { @@ -832,55 +826,55 @@ default: } ``` -A conditional expression -has the same behavior and syntax as an `if` statement or a `switch` statement, -except for the differences that the paragraphs below describe. +条件表达式 +的行为和语法与`if`语句或`switch`语句相同, +但以下段落描述的差异除外。 -A conditional expression appears only in the following contexts: +条件表达式仅出现在以下几种情况下: - - As the value assigned to a variable. - - As the initial value in a variable or constant declaration. - - As the error thrown by a `throw` expression. - - As the value returned by a function, closure, or property getter. - - As the value inside a branch of a conditional expression. +- 作为赋给变量的值。 +- 作为变量或常量声明中的初始值。 +- 作为`throw`表达式抛出的错误。 +- 作为函数、闭包或属性getter返回的值。 +- 作为条件表达式分支中的值。 -The branches of a conditional expression are exhaustive, -ensuring that the expression always produces a value -regardless of the condition. -This means each `if` branch needs a corresponding `else` branch. +条件表达式的分支是穷举的, +确保表达式总是产生一个值, +无论条件如何。 +这意味着每个`if`分支都需要一个对应的`else`分支。 -Each branch contains either a single expression, -which is used as the value for the conditional expression -when that branch's conditional is true, -a `throw` statement, -or a call to a function that never returns. +每个分支包含一个表达式, +当分支的条件为真时,该表达式用作条件表达式的值, -Each branch must produce a value of the same type. -Because type checking of each branch is independent, -you sometimes need to specify the value's type explicitly, -like when branches include different kinds of literals, -or when a branch's value is `nil`. -When you need to provide this information, -add a type annotation to the variable that the result is assigned to, -or add an `as` cast to the branches' values. +一个`throw`语句, +或对从不返回的函数的调用。 + +每个分支必须产生相同类型的值。 +由于每个分支的类型检查都是独立的, +有时需要明确指定值的类型, +例如当分支包含不同类型的字面量时, +或者当分支的值为`nil`时。 +当需要提供此信息时, +请在结果被分配到的变量上添加类型注释, +或者在分支的值上添加`as`转换. ```swift let number: Double = if someCondition { 10 } else { 12.34 } let number = if someCondition { 10 as Double } else { 12.34 } ``` -Inside a result builder, -conditional expressions can appear -only as the initial value of a variable or constant. -This behavior means when you write `if` or `switch` in a result builder --- -outside of a variable or constant declaration --- -that code is understood as a branch statement -and one of the result builder's methods transforms that code. +在结果生成器中, +条件表达式只能 +作为变量或常量的初始值出现。 +这意味着,当您在结果生成器中编写`if`或`switch`语句时—— +在变量或常量声明之外—— +该代码将被视为分支语句, +结果生成器的某个方法将转换该代码。 -Don't put a conditional expression in a `try` expression, -even if one of the branches of a conditional expression is throwing. +不要在`try`表达式中放置条件表达式, +即使条件表达式的分支之一正在抛出异常。 -> Grammar of a conditional expression: +> 条件句语法: > > *conditional-expression* → *if-expression* | *switch-expression* > @@ -893,15 +887,15 @@ even if one of the branches of a conditional expression is throwing. > *switch-expression-case* → *case-label* *statement* \ > *switch-expression-case* → *default-label* *statement* -### Closure Expression +### 结束语 表达 + +*闭包表达式*用于创建闭包, +在其他编程语言中也被称为*lambda*或*匿名函数*。 -A *closure expression* creates a closure, -also known as a *lambda* or an *anonymous function* -in other programming languages. -Like a function declaration, -a closure contains statements, -and it captures constants and variables from its enclosing scope. -It has the following form: +与函数声明类似, +闭包包含语句, +并捕获其外围作用域中的常量和变量。 +其形式如下: ```swift { (<#parameters#>) -> <#return type#> in @@ -909,12 +903,12 @@ It has the following form: } ``` -The *parameters* have the same form -as the parameters in a function declaration, -as described in . +*参数*的形式 +与函数声明中的参数相同, +如 . -Writing `throws` or `async` in a closure expression -explicitly marks a closure as throwing or asynchronous. +在闭包表达式中写上`throws`或 `async`, +即可明确标记闭包为抛出或异步。 ```swift { (<#parameters#>) async throws -> <#return type#> in @@ -922,36 +916,35 @@ explicitly marks a closure as throwing or asynchronous. } ``` -If the body of a closure includes a `throws` statement or a `try` expression -that isn't nested inside of a `do` statement with exhaustive error handling, -the closure is understood to be throwing. -If a throwing closure throws errors of only a single type, -the closure is understood as throwing that error type; -otherwise, it's understood as throwing `any Error`. -Likewise, if the body includes an `await` expression, -it's understood to be asynchronous. +如果闭包的体包含一个`throws`语句或一个`try`表达式, +且该语句或表达式未嵌套在具有详尽错误处理的`do`语句中, +则该闭包被视为抛出。 +如果抛出闭包仅抛出一种类型的错误, +则该闭包被视为抛出该错误类型; +否则,则被视为抛出“任何错误”。 +同样,如果体包含一个`await`表达式, +则理解为异步。 -There are several special forms -that allow closures to be written more concisely: +有几种特殊形式 +可以更简洁地编写闭包: -- A closure can omit the types - of its parameters, its return type, or both. - If you omit the parameter names and both types, - omit the `in` keyword before the statements. - If the omitted types can't be inferred, - a compile-time error is raised. -- A closure may omit names for its parameters. - Its parameters are then implicitly named - `$` followed by their position: - `$0`, `$1`, `$2`, and so on. -- A closure that consists of only a single expression - is understood to return the value of that expression. - The contents of this expression are also considered - when performing type inference on the surrounding expression. +- 闭包可以省略 +参数类型、返回类型或两者。 +如果省略了参数名称和两种类型, +请省略语句前的`in`关键字。 +如果省略的类型无法推断, +则会产生编译时错误。 +- 闭包可以省略参数名称。 +此时,参数的隐式命名 +为`$`后跟位置: +`$0`、`$1`、`$2`,以此类推。 +- 仅包含单个表达式的闭包 +会被理解为返回该表达式的值。 +在对周围表达式进行类型推断时,也会考虑该表达式的内容 -The following closure expressions are equivalent: +以下闭包表达式是等价的: ```swift myFunction { (x: Int, y: Int) -> Int in @@ -986,47 +979,45 @@ myFunction { $0 + $1 } ``` --> -For information about passing a closure as an argument to a function, -see . - -Closure expressions can be used -without being stored in a variable or constant, -such as when you immediately use a closure as part of a function call. -The closure expressions passed to `myFunction` in code above are -examples of this kind of immediate use. -As a result, -whether a closure expression is escaping or nonescaping depends -on the surrounding context of the expression. -A closure expression is nonescaping -if it's called immediately -or passed as a nonescaping function argument. -Otherwise, the closure expression is escaping. - -For more information about escaping closures, see . - -#### Capture Lists - -By default, a closure expression captures -constants and variables from its surrounding scope -with strong references to those values. -You can use a *capture list* to explicitly control -how values are captured in a closure. - -A capture list is written as a comma-separated list of expressions -surrounded by square brackets, -before the list of parameters. -If you use a capture list, you must also use the `in` keyword, -even if you omit the parameter names, parameter types, and return type. - -The entries in the capture list are initialized -when the closure is created. -For each entry in the capture list, -a constant is initialized -to the value of the constant or variable that has the same name -in the surrounding scope. -For example in the code below, -`a` is included in the capture list but `b` is not, -which gives them different behavior. +有关将闭合传递给函数的更多信息, +请参阅 . + +闭包表达式可以 +不存储在变量或常量中, +例如,当您立即将闭包用作函数调用的一部分时。 +在上述代码中传递给`myFunction`的闭包表达式是 +这种立即使用的示例。 +因此, +闭包表达式是转义还是非转义取决于 +表达式的上下文。 +如果立即调用 +或作为非转义函数参数传递。 +否则,闭包表达式为转义 +有关转义闭包的更多信息,请参阅. + +#### 捕捉列表 + +默认情况下,闭包表达式捕获 +其周围作用域中的常量和变量, +并对这些值进行强引用。 +您可以使用*捕获列表*来明确控制 +闭包中如何捕获值。 + +捕获列表以逗号分隔的表达式列表的形式书写, +用方括号括起来, +放在参数列表之前。 +如果使用捕获列表,则必须同时使用`in`关键字, +即使省略了参数名称、参数类型和返回类型。 + +捕获列表中的条目在 +创建闭包时初始化。 +对于捕获列表中的每个条目, +一个常量被初始化为 +周围作用域中具有相同名称的常量或变量的值。 + +例如,在下面的代码中, +`a`包含在捕获列表中,但`b`没有, +这导致它们的行为不同。 ```swift var a = 0 @@ -1058,21 +1049,20 @@ closure() ``` --> -There are two different things named `a`, -the variable in the surrounding scope -and the constant in the closure's scope, -but only one variable named `b`. -The `a` in the inner scope is initialized -with the value of the `a` in the outer scope -when the closure is created, -but their values aren't connected in any special way. -This means that a change to the value of `a` in the outer scope -doesn't affect the value of `a` in the inner scope, -nor does a change to `a` inside the closure -affect the value of `a` outside the closure. -In contrast, there's only one variable named `b` --- -the `b` in the outer scope --- -so changes from inside or outside the closure are visible in both places. +有两个不同的东西名为`a`, +一个是周围作用域中的变量, +一个是闭包作用域中的常量, +但只有一个变量名为`b`。 +当闭包创建时,内部作用域中的`a` +使用外部作用域中`a`的值进行初始化, +但它们的值没有以特殊方式连接。 +这意味着外部作用域中`a`的值发生变化 +不会影响内部作用域中`a`的值, +也不会影响闭包内部`a`的值。 + +相反,只有一个名为`b`的变量—— +外部作用域中的`b`—— +因此,闭包内部或外部所做的更改在两个地方都可见。 -This distinction isn't visible -when the captured variable's type has reference semantics. -For example, -there are two things named `x` in the code below, -a variable in the outer scope and a constant in the inner scope, -but they both refer to the same object -because of reference semantics. +当捕获的变量的类型具有引用语义时,这种区别是不可见的。 + +例如, +在下面的代码中,有两个名为`x`的东西, +一个是外层作用域中的变量,一个是内层作用域中的常量, +但它们都引用同一个对象, +因为引用语义 ```swift class SimpleClass { @@ -1160,10 +1150,10 @@ closure() ``` --> -If the type of the expression's value is a class, -you can mark the expression in a capture list -with `weak` or `unowned` to capture a weak or unowned reference -to the expression's value. +如果表达式值的类型是类, +则可以在捕获列表中用 +`weak`或`unowned`标记表达式,以捕获 +对表达式值的弱引用或非自有引用。. ```swift myFunction { print(self.title) } // implicit strong capture @@ -1193,11 +1183,11 @@ myFunction { [unowned self] in print(self.title) } // unowned capture ``` --> -You can also bind an arbitrary expression -to a named value in a capture list. -The expression is evaluated when the closure is created, -and the value is captured with the specified strength. -For example: +您还可以将任意表达式 +绑定到捕获列表中的命名值。 +表达式将在创建闭包时进行求值, +并以指定的强度捕获值。 +例如: ```swift // Weak capture of "self.parent" as "parent" @@ -1221,10 +1211,10 @@ myFunction { [weak parent = self.parent] in print(parent!.title) } ``` --> -For more information and examples of closure expressions, -see . -For more information and examples of capture lists, -see . +欲了解更多关于结束语的表达方式和示例, +请参阅 . +如需了解更多信息以及捕获列表示例, +请参阅. -> Grammar of a closure expression: +> 封闭表达的语法: > > *closure-expression* → **`{`** *attributes*_?_ *closure-signature*_?_ *statements*_?_ **`}`** > @@ -1265,20 +1255,20 @@ see *capture-list-item* → *capture-specifier*_?_ *self-expression* \ > *capture-specifier* → **`weak`** | **`unowned`** | **`unowned(safe)`** | **`unowned(unsafe)`** -### Implicit Member Expression +### 隐式成员表达式 -An *implicit member expression* -is an abbreviated way to access a member of a type, -such as an enumeration case or a type method, -in a context where type inference -can determine the implied type. -It has the following form: +*隐式成员表达式* +是一种访问类型成员的简写方式, +例如枚举情况或类型方法, +在类型推断 +可以确定隐式类型的情况下。 +它具有以下形式: ```swift .<#member name#> ``` -For example: +例如: ```swift var x = MyEnumeration.someValue @@ -1295,9 +1285,8 @@ x = .anotherValue ``` --> -If the inferred type is an optional, -you can also use a member of the non-optional type -in an implicit member expression. +如果推断的类型是可选的, +你也可以在隐式成员表达式中使用非可选类型的成员. ```swift var someOptional: MyEnumeration? = .someValue @@ -1311,20 +1300,20 @@ var someOptional: MyEnumeration? = .someValue ``` --> -Implicit member expressions can be followed by -a postfix operator or other postfix syntax listed in +隐式成员表达式后面可以跟 +后缀运算符或《指南》中列出的其他后缀语法 . -This is called a *chained implicit member expression*. -Although it's common for all of the chained postfix expressions -to have the same type, -the only requirement is that the whole chained implicit member expression -needs to be convertible to the type implied by its context. -Specifically, -if the implied type is an optional -you can use a value of the non-optional type, -and if the implied type is a class type -you can use a value of one of its subclasses. -For example: +这被称为“链式隐式成员表达式”。 +虽然所有链式后缀表达式通常 +具有相同的类型, +但唯一的要求是整个链式隐式成员表达式 +必须能够转换为其上下文隐含的类型。 +具体来说, +如果隐含类型是可选的, +则可以使用非可选类型的值, +如果隐含类型是类类型, +则可以使用其子类之一的值。 +例如: ```swift class SomeClass { @@ -1362,12 +1351,12 @@ let z: SomeClass = .sharedSubclass ``` --> -In the code above, -the type of `x` matches the type implied by its context exactly, -the type of `y` is convertible from `SomeClass` to `SomeClass?`, -and the type of `z` is convertible from `SomeSubclass` to `SomeClass`. +在上面的代码中, +`x`的类型与其上下文隐含的类型完全匹配, +`y`的类型可以从`SomeClass`转换为`SomeClass?`, +而`z`的类型可以从`SomeSubclass`转换为`SomeClass`。 -> Grammar of an implicit member expression: +> 隐式成员表达式的语法: > > *implicit-member-expression* → **`.`** *identifier* \ > *implicit-member-expression* → **`.`** *identifier* **`.`** *postfix-expression* @@ -1411,45 +1400,45 @@ and the type of `z` is convertible from `SomeSubclass` to `SomeClass`. ``` --> -### Parenthesized Expression +### 带括号的表达式 -A *parenthesized expression* consists of -an expression surrounded by parentheses. -You can use parentheses to specify the precedence of operations -by explicitly grouping expressions. -Grouping parentheses don't change an expression's type --- -for example, the type of `(1)` is simply `Int`. +A带*括号的表达式*由 +带括号的表达式组成。 +您可以使用括号来明确分组表达式, +从而指定运算的优先级。 +括号分组不会改变表达式的类型—— +例如,(1)的类型就是Int。 -> Grammar of a parenthesized expression: +> 带括号的表达式的语法: > > *parenthesized-expression* → **`(`** *expression* **`)`** -### Tuple Expression +### 元组表达式 -A *tuple expression* consists of -a comma-separated list of expressions surrounded by parentheses. -Each expression can have an optional identifier before it, -separated by a colon (`:`). -It has the following form: +一个*元组表达式*由 +一组用逗号分隔的表达式组成,并用括号括起来。 +每个表达式前都可以有一个可选的标识符, +用冒号(`:`)隔开。 +其格式如下: ```swift (<#identifier 1#>: <#expression 1#>, <#identifier 2#>: <#expression 2#>, <#...#>) ``` -Each identifier in a tuple expression must be unique -within the scope of the tuple expression. -In a nested tuple expression, -identifiers at the same level of nesting must be unique. -For example, -`(a: 10, a: 20)` is invalid -because the label `a` appears twice at the same level. -However, `(a: 10, b: (a: 1, x: 2))` is valid --- -although `a` appears twice, -it appears once in the outer tuple and once in the inner tuple. +元组表达式中的每个标识符在 +元组表达式的范围内必须是唯一的。 +在嵌套元组表达式中, +同一嵌套级别的标识符必须是唯一的。 +例如, +`(a: 10, a: 20)` 是无效的, +因为标签 `a` 在同一级别出现了两次。 +然而,`(a: 10, b: (a: 1, x: 2))`是有效的—— +尽管`a`出现了两次, +但一次出现在外层元组中,一次出现在内层元组中。 -A tuple expression can contain zero expressions, -or it can contain two or more expressions. -A single expression inside parentheses is a parenthesized expression. +一个元组表达式可以包含零个表达式, +也可以包含两个或更多表达式。 +括号内的单个表达式是一个带括号的表达式。 -> Note: Both an empty tuple expression and an empty tuple type -> are written `()` in Swift. -> Because `Void` is a type alias for `()`, -> you can use it to write an empty tuple type. -> However, like all type aliases, `Void` is always a type --- -> you can't use it to write an empty tuple expression. +> 注意:在Swift中,空元组表达式和空元组类型 +> 都写成`()`。 +> 因为`Void`是`()`的类型别名, +> 所以可以用它来表示空元组类型。 +> 然而,像所有类型别名一样,`Void`始终是一个类型—— +> 不能用它来表示空元组表达式。 -> Grammar of a tuple expression: +> 元组表达式的语法: > > *tuple-expression* → **`(`** **`)`** | **`(`** *tuple-element* **`,`** *tuple-element-list* **`)`** \ > *tuple-element-list* → *tuple-element* | *tuple-element* **`,`** *tuple-element-list* \ > *tuple-element* → *expression* | *identifier* **`:`** *expression* -### Wildcard Expression +### 通配符表达式 -A *wildcard expression* -is used to explicitly ignore a value during an assignment. -For example, in the following assignment -10 is assigned to `x` and 20 is ignored: +*通配符表达式* +用于在赋值期间明确忽略某个值。 +例如,在以下赋值中 +10被赋给`x`,而20被忽略: ```swift (x, _) = (10, 20) @@ -1502,111 +1491,110 @@ For example, in the following assignment ``` --> -> Grammar of a wildcard expression: +> 通配符表达式的语法: > > *wildcard-expression* → **`_`** -### Macro-Expansion Expression +### 宏扩展表达式 -A *macro-expansion expression* consists of a macro name -followed by a comma-separated list of the macro's arguments in parentheses. -The macro is expanded at compile time. -Macro-expansion expressions have the following form: +*宏扩展表达式*由宏名称 +后跟以逗号分隔的宏参数列表(括号内)组成。 +宏在编译时扩展。 +宏扩展表达式具有以下形式: ```swift <#macro name#>(<#macro argument 1#>, <#macro argument 2#>) ``` -A macro-expansion expression omits the parentheses after the macro's name -if the macro doesn't take any arguments. +宏扩展表达式省略了宏名称后的括号, +如果宏不接收任何参数。 -A macro-expansion expression can't appear as the default value for a parameter, -except the [`file()`][] and [`line()`][] macros from the Swift standard library. -When used as the default value of a function or method parameter, -these macros are evaluated using the source code location of the call site, -not the location where they appear in a function definition. +宏扩展表达式不能作为参数的默认值出现, +Swift标准库中的[`file()`][]和[`line()`][]宏除外。 +当用作函数或方法参数的默认值时, +这些宏的计算使用调用位置的源代码位置, +而不是它们在函数定义中的位置. [`file()`]: https://developer.apple.com/documentation/swift/file() [`line()`]: https://developer.apple.com/documentation/swift/line() -You use macro expressions to call freestanding macros. -To call an attached macro, -use the custom attribute syntax described in . -Both freestanding and attached macros expand as follows: +使用宏表达式调用独立宏。 +要调用附加宏, +请使用自定义属性语法,如 . +独立宏和附加宏的扩展方式如下: -1. Swift parses the source code - to produce an abstract syntax tree (AST). +1. Swift解析源代码 +以生成抽象语法树(AST)。 -2. The macro implementation receives AST nodes as its input - and performs the transformations needed by that macro. +2. 宏执行将AST节点作为输入 +并执行该宏所需的转换。 -3. The transformed AST nodes that the macro implementation produced - are added to the original AST. +3. 宏执行生成的转换后的AST节点 +将添加到原始的AST中。 -The expansion of each macro is independent and self-contained. -However, as a performance optimization, -Swift might start an external process that implements the macro -and reuse the same process to expand multiple macros. -When you implement a macro, -that code must not depend on what macros your code previously expanded, -or on any other external state like the current time. +每个宏的扩展都是独立且自包含的。 +然而,作为性能优化, +Swift可能会启动一个外部进程来执行宏, +并重复使用相同的进程来扩展多个宏。 +当您执行宏时, +该代码不能依赖于您的代码之前扩展的宏, +或任何其他外部状态,如当前时间。 -For nested macros and attached macros that have multiple roles, -the expansion process repeats. -Nested macro-expansion expressions expand from the outside in. -For example, in the code below -`outerMacro(_:)` expands first and the unexpanded call to `innerMacro(_:)` -appears in the abstract syntax tree -that `outerMacro(_:)` receives as its input. +对于具有多重作用的嵌套宏和附加宏, +扩展过程会重复进行。 +嵌套宏扩展表达式从外向内扩展。 +例如,在以下代码中 +`outerMacro(_:)`首先扩展,而未扩展的`innerMacro(_:)`调用 +出现在抽象语法树中, +作为输入传递给`outerMacro(_:)` ```swift #outerMacro(12, #innerMacro(34), "some text") ``` -An attached macro that has multiple roles expands once for each role. -Each expansion receives the same, original, AST as its input. -Swift forms the overall expansion -by collecting all of the generated AST nodes -and putting them in their corresponding places in the AST. +一个具有多种作用的附加宏会为每个作用扩展一次。 +每次扩展都会收到相同的原始抽象语法树作为输入。 +Swift通过收集所有生成的抽象语法树节点 +并将其放置在抽象语法树中的相应位置 +来形成整体扩展. -For an overview of macros in Swift, see . +有关Swift宏的概述,请参阅 . -> Grammar of a macro-expansion expression: +> 宏扩展表达式的语法: > > *macro-expansion-expression* → **`#`** *identifier* *generic-argument-clause*_?_ *function-call-argument-clause*_?_ *trailing-closures*_?_ -### Key-Path Expression +### 关键路径表达式 -A *key-path expression* -refers to a property or subscript of a type. -You use key-path expressions -in dynamic programming tasks, -such as key-value observing. -They have the following form: +*键路径表达式* +是指一个类型的属性或下标。 +您可以在动态编程任务中使用键路径表达式, +例如键值观察。 +它们具有以下形式: ```swift \<#type name#>.<#path#> ``` -The *type name* is the name of a concrete type, -including any generic parameters, -such as `String`, `[Int]`, or `Set`. +*类型名称*是具体类型的名称, +包括任何通用参数, +例如`String`、`[Int]`或`Set`。 -The *path* consists of -property names, subscripts, optional-chaining expressions, -and forced unwrapping expressions. -Each of these key-path components -can be repeated as many times as needed, -in any order. +*路径*由 +属性名称、下标、可选链式表达式和 +强制解包表达式组成。 +这些关键路径组件中的每一个 +都可以根据需要重复任意次数, +且顺序不限。 -At compile time, a key-path expression -is replaced by an instance -of the [`KeyPath`](https://developer.apple.com/documentation/swift/keypath) class. +在编译时,关键路径表达式 +会被替换为 + [`KeyPath`](https://developer.apple.com/documentation/swift/keypath) 类 -To access a value using a key path, -pass the key path to the `subscript(keyPath:)` subscript, -which is available on all types. -For example: +要使用键路径访问一个值, +请将键路径传递给`下标(keyPath:)`下标, +该下标适用于所有类型。 +例如: -The *type name* can be omitted -in contexts where type inference -can determine the implied type. -The following code uses `\.someProperty` -instead of `\SomeClass.someProperty`: +在类型推断 +可以确定隐含类型的情况下,可以省略 +类型名称。 +以下代码使用`\.someProperty` +代替`\SomeClass.someProperty` : ```swift class SomeClass: NSObject { @@ -1689,11 +1677,14 @@ c.observe(\.someProperty) { object, change in Tracking bug is --> -The *path* can refer to `self` to create the identity key path (`\.self`). -The identity key path refers to a whole instance, -so you can use it to access and change all of the data stored in a variable -in a single step. -For example: +*路径*可以包含多个属性名称, +以句点分隔, +以引用属性值的属性。 +此代码使用关键路径表达式 +`\OuterStructure.outer.someValue` +来访问 +`OuterStructure`类型`outer`属性的 +`someValue`属性: ```swift var compoundValue = (a: 1, b: 2) @@ -1711,13 +1702,14 @@ compoundValue[keyPath: \.self] = (a: 10, b: 20) ``` --> -The *path* can contain multiple property names, -separated by periods, -to refer to a property of a property's value. -This code uses the key path expression +*路径*可以包含多个属性名称, +以句点分隔, +以引用属性值的属性。 +此代码使用关键路径表达式 `\OuterStructure.outer.someValue` -to access the `someValue` property -of the `OuterStructure` type's `outer` property: +来访问 +`OuterStructure`类型`outer`属性的 +`someValue`属性: ```swift struct OuterStructure { @@ -1754,10 +1746,10 @@ let nestedValue = nested[keyPath: nestedKeyPath] ``` --> -The *path* can include subscripts using brackets, -as long as the subscript's parameter type conforms to the `Hashable` protocol. -This example uses a subscript in a key path -to access the second element of an array: +*路径*可以使用括号包含下标, +只要下标的参数类型符合可哈希(Hashable)协议即可。 +本例在键路径中使用下标 +来访问数组的第二个元素: ```swift let greetings = ["hello", "hola", "bonjour", "안녕"] @@ -1783,14 +1775,14 @@ let myGreeting = greetings[keyPath: \[String].[1]] [SR-5865]: Key path expression is "ambiguous without more context" --> -The value used in a subscript can be a named value or a literal. -Values are captured in key paths using value semantics. -The following code uses the variable `index` -in both a key-path expression and in a closure to access -the third element of the `greetings` array. -When `index` is modified, -the key-path expression still references the third element, -while the closure uses the new index. +下标中使用的值可以是命名值或文字。 +使用值语义在键路径中捕获值。 +以下代码在键路径表达式和闭包中均使用变量`index` +来访问 +`greetings`数组的第三个元素。 +当修改`index`时, +键路径表达式仍引用第三个元素, +而闭包使用新的索引. ```swift var index = 2 @@ -1836,9 +1828,8 @@ print(fn(greetings)) ``` --> -The *path* can use optional chaining and forced unwrapping. -This code uses optional chaining in a key path -to access a property of an optional string: +*路径*可以使用可选链和强制解包。 +这段代码在键: ```swift let firstGreeting: String? = greetings.first @@ -1871,12 +1862,11 @@ print(count as Any) Swift 5.2 regression in keypaths --> -You can mix and match components of key paths to access values -that are deeply nested within a type. -The following code accesses different values and properties -of a dictionary of arrays -by using key-path expressions -that combine these components. +您可以混合和匹配关键路径的组件,以访问 +嵌套在类型中的 +值。以下代码通过组合这些组件的关键路径表达式 +访问数组字典 +的不同值和属性. ```swift let interestingNumbers = ["prime": [2, 3, 5, 7, 11, 13, 17], @@ -1910,13 +1900,14 @@ print(interestingNumbers[keyPath: \[String: [Int]].["hexagonal"]!.count.bitWidth ``` --> -You can use a key path expression -in contexts where you would normally provide a function or closure. -Specifically, -you can use a key path expression -whose root type is `SomeType` -and whose path produces a value of type `Value`, -instead of a function or closure of type `(SomeType) -> Value`. +您可以在通常提供函数或闭包的上下文中使用键路径表达式。 + +具体来说, +您可以使用 +根类型为 `SomeType` +且路径生成`Value`类型值的 +键路径表达式, +而不是`(SomeType) -> Value`类型的函数或闭包. ```swift struct Task { @@ -1961,12 +1952,12 @@ let descriptions2 = toDoList.filter { $0.completed }.map { $0.description } "The Pirates Who Don't Do Anything". --> -Any side effects of a key path expression -are evaluated only at the point where the expression is evaluated. -For example, -if you make a function call inside a subscript in a key path expression, -the function is called only once as part of evaluating the expression, -not every time the key path is used. +关键路径表达式的任何副作用 +仅在表达式被评估时进行评估。 +例如, +如果您在关键路径表达式中的下标内进行函数调用, +则该函数仅在评估表达式时调用一次, +而不是在每次使用关键路径时调用. ```swift func makeIndex() -> Int { @@ -2000,14 +1991,14 @@ let someTask = toDoList[keyPath: taskKeyPath] ``` --> -For more information about using key paths -in code that interacts with Objective-C APIs, -see [Using Objective-C Runtime Features in Swift](https://developer.apple.com/documentation/swift/using_objective_c_runtime_features_in_swift). -For information about key-value coding and key-value observing, -see [Key-Value Coding Programming Guide](https://developer.apple.com/library/content/documentation/Cocoa/Conceptual/KeyValueCoding/index.html#//apple_ref/doc/uid/10000107i) -and [Key-Value Observing Programming Guide](https://developer.apple.com/library/content/documentation/Cocoa/Conceptual/KeyValueObserving/KeyValueObserving.html#//apple_ref/doc/uid/10000177i). +如需了解有关在 +与Objective-C API交互的代码中使用关键路径的更多信息, +请参阅 [Using Objective-C Runtime Features in Swift](https://developer.apple.com/documentation/swift/using_objective_c_runtime_features_in_swift). +有关键值编码和键值观察的信息, +请参阅[Key-Value Coding Programming Guide](https://developer.apple.com/library/content/documentation/Cocoa/Conceptual/KeyValueCoding/index.html#//apple_ref/doc/uid/10000107i) +和 [Key-Value Observing Programming Guide](https://developer.apple.com/library/content/documentation/Cocoa/Conceptual/KeyValueObserving/KeyValueObserving.html#//apple_ref/doc/uid/10000177i). -> Grammar of a key-path expression: +> 键路径表达式的语法: > > *key-path-expression* → **`\`** *type*_?_ **`.`** *key-path-components* \ > *key-path-components* → *key-path-component* | *key-path-component* **`.`** *key-path-components* \ @@ -2016,12 +2007,12 @@ and [Key-Value Observing Programming Guide](https://developer.apple.com/library/ > *key-path-postfixes* → *key-path-postfix* *key-path-postfixes*_?_ \ > *key-path-postfix* → **`?`** | **`!`** | **`self`** | **`[`** *function-call-argument-list* **`]`** -### Selector Expression +### 选择器 表达 -A selector expression lets you access the selector -used to refer to a method or to a property's -getter or setter in Objective-C. -It has the following form: +选择器表达式允许您访问 +Objective-C中用于引用方法或属性 +getter或setter的选择器。 +其格式如下: ```swift #selector(<#method name#>) @@ -2029,10 +2020,10 @@ It has the following form: #selector(setter: <#property name#>) ``` -The *method name* and *property name* must be a reference to a method or a property -that's available in the Objective-C runtime. -The value of a selector expression is an instance of the `Selector` type. -For example: +*方法名*和*属性名*必须引用 +Objective-C运行时中可用 +的某个方法或属性。选择器表达式的值是`Selector`类型的实例。 +例如: ```swift class SomeClass: NSObject { @@ -2069,15 +2060,15 @@ let selectorForPropertyGetter = #selector(getter: SomeClass.property) ``` --> -When creating a selector for a property's getter, -the *property name* can be a reference to a variable or constant property. -In contrast, when creating a selector for a property's setter, -the *property name* must be a reference to a variable property only. +在为属性的getter创建选择器时, +*属性名称*可以是指向变量或常量属性的引用。 +相反,在为属性的setter创建选择器时, +*属性名称*必须仅是指向变量属性的引用。 -The *method name* can contain parentheses for grouping, -as well the `as` operator to disambiguate between methods that share a name -but have different type signatures. -For example: +*方法名称*可以包含用于分组的括号, +以及用于区分同名但类型不同的方法的`as`运算符 + +例如: ```swift extension SomeClass { @@ -2108,16 +2099,16 @@ let anotherSelector = #selector(SomeClass.doSomething(_:) as (SomeClass) -> (Str ``` --> -Because a selector is created at compile time, not at runtime, -the compiler can check that a method or property exists -and that they're exposed to the Objective-C runtime. +因为选择器是在编译时创建的,而不是在运行时创建的, +编译器可以检查方法或属性是否存在 +以及它们是否暴露给Objective-C运行时. > Note: Although the *method name* and the *property name* are expressions, > they're never evaluated. -For more information about using selectors -in Swift code that interacts with Objective-C APIs, -see [Using Objective-C Runtime Features in Swift](https://developer.apple.com/documentation/swift/using_objective_c_runtime_features_in_swift). +如需了解如何使用选择器 +在Swift代码中与Objective-C API交互, +请参阅[Using Objective-C Runtime Features in Swift](https://developer.apple.com/documentation/swift/using_objective_c_runtime_features_in_swift). > Grammar of a selector expression: > @@ -2132,21 +2123,21 @@ see [Using Objective-C Runtime Features in Swift](https://developer.apple.com/do optional binding. --> -### Key-Path String Expression +### 键路径字符串表达式 -A key-path string expression lets you access the string -used to refer to a property in Objective-C, -for use in key-value coding and key-value observing APIs. -It has the following form: +键路径字符串表达式允许您访问 +用于在Objective-C中引用属性的字符串, +用于键值编码和键值观察API。 +其格式如下: ```swift #keyPath(<#property name#>) ``` -The *property name* must be a reference to a property -that's available in the Objective-C runtime. -At compile time, the key-path string expression is replaced by a string literal. -For example: +*属性名称*必须引用 +Objective-C运行时中可用的 +属性。在编译时,键路径字符串表达式将被替换为字符串字面量。 +例如: ```swift class SomeClass: NSObject { @@ -2187,9 +2178,9 @@ if let value = c.value(forKey: keyPath) { ``` --> -When you use a key-path string expression within a class, -you can refer to a property of that class -by writing just the property name, without the class name. +当您在类中使用键路径字符串表达式时, +只需写上属性名称即可引用该类的属性, +而无需写上类名称 ```swift extension SomeClass { @@ -2215,16 +2206,16 @@ print(keyPath == c.getSomeKeyPath()) ``` --> -Because the key path string is created at compile time, not at runtime, -the compiler can check that the property exists -and that the property is exposed to the Objective-C runtime. +因为键路径字符串是在编译时创建的,而不是在运行时创建的, +编译器可以检查属性是否存在 +以及该属性是否暴露给Objective-C运行时。 -For more information about using key paths -in Swift code that interacts with Objective-C APIs, -see [Using Objective-C Runtime Features in Swift](https://developer.apple.com/documentation/swift/using_objective_c_runtime_features_in_swift). -For information about key-value coding and key-value observing, -see [Key-Value Coding Programming Guide](https://developer.apple.com/library/content/documentation/Cocoa/Conceptual/KeyValueCoding/index.html#//apple_ref/doc/uid/10000107i) -and [Key-Value Observing Programming Guide](https://developer.apple.com/library/content/documentation/Cocoa/Conceptual/KeyValueObserving/KeyValueObserving.html#//apple_ref/doc/uid/10000177i). +如需了解如何使用 +Swift代码中的关键路径与Objective-C API交互, +请参阅[Using Objective-C Runtime Features in Swift](https://developer.apple.com/documentation/swift/using_objective_c_runtime_features_in_swift). +有关键值编码和键值观察的信息, +请参阅 [Key-Value Coding Programming Guide](https://developer.apple.com/library/content/documentation/Cocoa/Conceptual/KeyValueCoding/index.html#//apple_ref/doc/uid/10000107i) +和 [Key-Value Observing Programming Guide](https://developer.apple.com/library/content/documentation/Cocoa/Conceptual/KeyValueObserving/KeyValueObserving.html#//apple_ref/doc/uid/10000177i). > Note: Although the *property name* is an expression, it's never evaluated. @@ -2232,20 +2223,20 @@ and [Key-Value Observing Programming Guide](https://developer.apple.com/library/ > > *key-path-string-expression* → **`#keyPath`** **`(`** *expression* **`)`** -## Postfix Expressions +## 后缀表达式 -*Postfix expressions* are formed -by applying a postfix operator or other postfix syntax -to an expression. -Syntactically, every primary expression is also a postfix expression. +*后缀表达式*是通过 +将后缀运算符或其他后缀语法 +应用到表达式来形成的。 +从语法上讲,每个主要表达式也是后缀表达式。 -For information about the behavior of these operators, -see and . +有关这些运算符的行为, +请参阅 and . -For information about the operators provided by the Swift standard library, -see [Operator Declarations](https://developer.apple.com/documentation/swift/operator_declarations). +有关Swift标准库提供的操作符的信息, +请参阅[Operator Declarations](https://developer.apple.com/documentation/swift/operator_declarations). -> Grammar of a postfix expression: +> 后缀表达式的语法: > > *postfix-expression* → *primary-expression* \ > *postfix-expression* → *postfix-expression* *postfix-operator* \ @@ -2257,40 +2248,40 @@ see [Operator Declarations](https://developer.apple.com/documentation/swift/oper > *postfix-expression* → *forced-value-expression* \ > *postfix-expression* → *optional-chaining-expression* -### Function Call Expression +### 函数调用表达式 -A *function call expression* consists of a function name -followed by a comma-separated list of the function's arguments in parentheses. -Function call expressions have the following form: +*函数调用表达式*由函数名称 +后跟以逗号分隔的函数参数列表组成,参数列表放在括号内。 +函数调用表达式具有以下形式: ```swift <#function name#>(<#argument value 1#>, <#argument value 2#>) ``` -The *function name* can be any expression whose value is of a function type. +*函数名称*可以是任何表达式,其值是函数类型。 -If the function definition includes names for its parameters, -the function call must include names before its argument values, -separated by a colon (`:`). -This kind of function call expression has the following form: +如果函数定义包括其参数的名称, +则函数调用必须在参数值之前包含名称, +并用冒号(`:`)分隔。 +这种函数调用表达式具有以下形式: ```swift <#function name#>(<#argument name 1#>: <#argument value 1#>, <#argument name 2#>: <#argument value 2#>) ``` -A function call expression can include trailing closures -in the form of closure expressions immediately after the closing parenthesis. -The trailing closures are understood as arguments to the function, -added after the last parenthesized argument. -The first closure expression is unlabeled; -any additional closure expressions are preceded by their argument labels. -The example below shows the equivalent version of function calls -that do and don't use trailing closure syntax: +函数调用表达式可以包含 +紧接在右括号之后的闭包表达式形式的尾部闭包。 +尾部闭包被理解为函数的参数, +添加在最后一个带括号的参数之后。 +第一个闭包表达式没有标签; +任何附加的闭包表达式前面都有其参数标签。 +下面的示例显示了 +使用和不使用尾部闭包语法的函数调用的等效版本: ```swift // someFunction takes an integer and a closure as its arguments @@ -2338,8 +2329,8 @@ anotherFunction(x: x) { $0 == 13 } g: { print(99) } Tracking bug is --> -If the trailing closure is the function's only argument, -you can omit the parentheses. +如果尾随闭合是该函数的唯一参数, +则可以省略括号. ```swift // someMethod takes a closure as its only argument @@ -2373,46 +2364,46 @@ myData.someMethod { $0 == 13 } Tracking bug is --> -To include the trailing closures in the arguments, -the compiler examines the function's parameters from left to right as follows: +为了在参数中包含尾部闭合, +编译器从左到右检查函数的参数,如下所示: -| Trailing Closure | Parameter | Action | +| 尾随关闭 | 参数 | 行为 | | ---------------- | --------- | ------ | -| Labeled | Labeled | If the labels are the same, the closure matches the parameter; otherwise, the parameter is skipped. | -| Labeled | Unlabeled | The parameter is skipped. | -| Unlabeled | Labeled or unlabeled | If the parameter structurally resembles a function type, as defined below, the closure matches the parameter; otherwise, the parameter is skipped. | - -The trailing closure is passed as the argument for the parameter that it matches. -Parameters that were skipped during the scanning process -don't have an argument passed to them --- -for example, they can use a default parameter. -After finding a match, scanning continues -with the next trailing closure and the next parameter. -At the end of the matching process, -all trailing closures must have a match. - -A parameter *structurally resembles* a function type -if the parameter isn't an in-out parameter, -and the parameter is one of the following: - -- A parameter whose type is a function type, - like `(Bool) -> Int` -- An autoclosure parameter - whose wrapped expression's type is a function type, - like `@autoclosure () -> ((Bool) -> Int)` -- A variadic parameter - whose array element type is a function type, - like `((Bool) -> Int)...` -- A parameter whose type is wrapped in one or more layers of optional, - like `Optional<(Bool) -> Int>` -- A parameter whose type combines these allowed types, - like `(Optional<(Bool) -> Int>)...` - -When a trailing closure is matched to a parameter -whose type structurally resembles a function type, but isn't a function, -the closure is wrapped as needed. -For example, if the parameter's type is an optional type, -the closure is wrapped in `Optional` automatically. +| 贴标签 | 贴标签| 如果标签相同,则封口与参数匹配; 否则,参数将被跳过. | +| 有标签 | 无标签 | 跳过参数 | +| 无标签 | 有标签或无标签 | 如果参数在结构上类似于如下定义的函数类型,则闭包与参数匹配;否则,跳过该参数. | + +尾随闭包作为参数传递给它匹配的参数。 +在扫描过程中跳过的参数 +没有传递给它们的参数 --- +例如,它们可以使用默认参数。 +找到匹配项后,扫描继续 +下一个尾随闭包和下一个参数。 +在匹配过程结束时, +所有尾随闭包都必须有匹配项。 + +如果参数不是输入输出参数,则该参数在结构上与函数类型 +类似, +且该参数属于以下类型之一: + +- 类型为函数类型的参数, +如 `(Bool) -> Int` +- 自动闭包参数, +其包装表达式的类型为函数类型, +如 `@autoclosure () -> ((Bool) -> Int)` +- 可变参数, +其数组元素类型为函数类型, +如 `((Bool) -> Int)...` +- 类型被一层或多层可选包装的参数, +如 `Optional<(Bool) -> Int>` +- 参数类型结合了这些允许的类型, +如 `(Optional<(Bool) -> Int>)...` + +当尾随闭包与参数匹配时, +其类型在结构上类似于函数类型,但不是函数, +则根据需要包装闭包。 +例如,如果参数的类型是可选类型, +则自动将闭包包装在 `Optional` 中. -To ease migration of code from versions of Swift prior to 5.3 --- -which performed this matching from right to left --- -the compiler checks both the left-to-right and right-to-left orderings. -If the scan directions produce different results, -the old right-to-left ordering is used -and the compiler generates a warning. -A future version of Swift will always use the left-to-right ordering. +为了简化从Swift 5.3之前的版本迁移代码的过程—— +该版本从右向左进行匹配—— +编译器会同时检查从左向右和从右向左的顺序。 +如果扫描方向产生不同的结果, +则使用旧的从右向左顺序, +编译器会生成警告。 +未来的Swift版本将始终使用从左向右的顺序. ```swift typealias Callback = (Int) -> Int @@ -2489,36 +2480,36 @@ someFunction { return $0 } secondClosure: { return $0 } // Prints "10 20" ``` --> -In the example above, -the function call marked "Ambiguous" -prints "- 120" and produces a compiler warning on Swift 5.3. -A future version of Swift will print “110 -”. +在上面的例子中, +标记为'Ambiguous'的函数调用 +在Swift 5.3上打印“- 120”并产生编译器警告。 +未来版本的Swift将打印'110 -'. -A class, structure, or enumeration type -can enable syntactic sugar for function call syntax -by declaring one of several methods, -as described in . +类、结构或枚举类型 +可通过声明多种方法之一, +为函数调用语法提供语法糖, +如 . -#### Implicit Conversion to a Pointer Type +#### 隐式转换为指针类型 -In a function call expression, -if the argument and parameter have a different type, -the compiler tries to make their types match -by applying one of the implicit conversions in the following list: +在函数调用表达式中, +如果参数和参数的类型不同, +编译器会尝试通过 +应用以下列表中的隐式转换之一来使它们的类型匹配: -- `inout SomeType` can become - `UnsafePointer` or `UnsafeMutablePointer` -- `inout Array` can become - `UnsafePointer` or `UnsafeMutablePointer` -- `Array` can become `UnsafePointer` -- `String` can become `UnsafePointer` +- `inout SomeType` 可以成为 +`UnsafePointer` 或 `UnsafeMutablePointer` +- `inout Array` 可以成为 +`UnsafePointer`或`UnsafeMutablePointer` +- `Array`可以成为`UnsafePointer` +- `String`可以成为`UnsafePointer` -The following two function calls are equivalent: +以下两个函数调用是等价的: ```swift func unsafeFunction(pointer: UnsafePointer) { @@ -2547,11 +2538,11 @@ withUnsafePointer(to: myNumber) { unsafeFunction(pointer: $0) } ``` --> -A pointer that's created by these implicit conversions -is valid only for the duration of the function call. -To avoid undefined behavior, -ensure that your code -never persists the pointer after the function call ends. +这些隐式转换创建的指针 +仅在函数调用期间有效。 +为避免出现未定义行为, +请确保您的代码 +在函数调用结束后不会保留指针. > Note: When implicitly converting an array to an unsafe pointer, > Swift ensures that the array's storage is contiguous @@ -2563,11 +2554,11 @@ never persists the pointer after the function call ends. > so the implicit conversion never needs to do this work, > use `ContiguousArray` instead of `Array`. -Using `&` instead of an explicit function like `withUnsafePointer(to:)` -can help make calls to low-level C functions more readable, -especially when the function takes several pointer arguments. -However, when calling functions from other Swift code, -avoid using `&` instead of using the unsafe APIs explicitly. +使用`&`代替`withUnsafePointer(to:)`等显式函数 +有助于提高低级C函数调用的可读性, +尤其是当函数需要多个指针参数时。 +然而,当从其他Swift代码调用函数时, +应避免使用`&`代替显式使用不安全的API. -> Grammar of a function call expression: +> 函数调用表达式的语法: > > *function-call-expression* → *postfix-expression* *function-call-argument-clause* \ > *function-call-expression* → *postfix-expression* *function-call-argument-clause*_?_ *trailing-closures* @@ -2627,20 +2618,20 @@ avoid using `&` instead of using the unsafe APIs explicitly. > *labeled-trailing-closures* → *labeled-trailing-closure* *labeled-trailing-closures*_?_ \ > *labeled-trailing-closure* → *identifier* **`:`** *closure-expression* -### Initializer Expression +### 初始化表达式 -An *initializer expression* provides access -to a type's initializer. -It has the following form: +*初始化表达式*用于访问 +类型的初始化器。 +其形式如下: ```swift <#expression#>.init(<#initializer arguments#>) ``` -You use the initializer expression in a function call expression -to initialize a new instance of a type. -You also use an initializer expression -to delegate to the initializer of a superclass. +在函数调用表达式中使用初始化表达式 +来初始化一个类型的新实例。 +还可以使用初始化表达式 +来委托给超类的初始化器. ```swift class SomeSubClass: SomeSuperClass { @@ -2665,8 +2656,8 @@ class SomeSubClass: SomeSuperClass { ``` --> -Like a function, an initializer can be used as a value. -For example: +初始化器可以像函数一样用作值。 +例如: ```swift // Type annotation is required because String has multiple initializers. @@ -2688,9 +2679,9 @@ print(oneTwoThree) ``` --> -If you specify a type by name, -you can access the type's initializer without using an initializer expression. -In all other cases, you must use an initializer expression. +如果您指定了类型名称, +则无需使用初始化表达式即可访问该类型的初始化程序。 +在其他情况下,您必须使用初始化表达式. ```swift let s1 = SomeType.init(data: 3) // Valid @@ -2720,25 +2711,25 @@ let s4 = type(of: someValue)(data: 5) // Error ``` --> -> Grammar of an initializer expression: +> 初始化表达式的语法: > > *initializer-expression* → *postfix-expression* **`.`** **`init`** \ > *initializer-expression* → *postfix-expression* **`.`** **`init`** **`(`** *argument-names* **`)`** -### Explicit Member Expression +### 明确的会员表达 -An *explicit member expression* allows access -to the members of a named type, a tuple, or a module. -It consists of a period (`.`) between the item -and the identifier of its member. +*显式成员表达式*允许访问 +已命名类型、元组或模块的成员。 +它由句点(`.`)分隔, +位于项目与其成员标识符之间. ```swift <#expression#>.<#member name#> ``` -The members of a named type are named -as part of the type's declaration or extension. -For example: +命名类型的成员在 +类型声明或扩展中命名。 +例如: ```swift class SomeClass { @@ -2760,10 +2751,10 @@ let y = c.someProperty // Member access ``` --> -The members of a tuple -are implicitly named using integers in the order they appear, -starting from zero. -For example: +元组的成员 +按出现顺序用整数隐式命名, +从0开始。 +例如: ```swift var t = (10, 20, 30) @@ -2781,21 +2772,21 @@ t.0 = t.1 ``` --> -The members of a module access -the top-level declarations of that module. +模块的成员可以访问 +该模块的顶层声明。 + +使用`dynamicMemberLookup`属性声明的类型 +包括在运行时查找的成员, +如 . -Types declared with the `dynamicMemberLookup` attribute -include members that are looked up at runtime, -as described in . +为了区分名称仅因参数名称而不同的方法或初始化器, -To distinguish between methods or initializers -whose names differ only by the names of their arguments, -include the argument names in parentheses, -with each argument name followed by a colon (`:`). -Write an underscore (`_`) for an argument with no name. -To distinguish between overloaded methods, -use a type annotation. -For example: +请将参数名称放在括号内, +每个参数名称后加一个冒号(`:`)。 +对于没有名称的参数,请写一个下划线(`_`)。 +为了区分重载方法, +请使用类型注释。 +例如: ```swift class SomeClass { @@ -2862,11 +2853,11 @@ let d: (Int, Bool) -> Void = instance.overloadedMethod(x:y:) // Unambiguous ``` --> -If a period appears at the beginning of a line, -it's understood as part of an explicit member expression, -not as an implicit member expression. -For example, the following listing shows chained method calls -split over several lines: +如果一行开头出现句点, +则应理解为显式成员表达式的一部分, +而非隐式成员表达式。 +例如,以下列表显示了 +分几行显示的链式方法调用: ```swift let x = [10, 3, 20, 15, 4] @@ -2888,11 +2879,11 @@ let x = [10, 3, 20, 15, 4] ``` --> -You can combine this multiline chained syntax -with compiler control statements -to control when each method is called. -For example, -the following code uses a different filtering rule on iOS: +您可以将这种多行链式语法 +与编译器控制语句 +相结合,以控制每个方法的调用时间。 +例如, +以下代码在iOS上使用不同的过滤规则: ```swift let numbers = [10, 20, 33, 43, 50] @@ -2918,23 +2909,23 @@ let numbers = [10, 20, 33, 43, 50] ``` --> -Between `#if`, `#endif`, and other compilation directives, -the conditional compilation block can contain -an implicit member expression -followed by zero or more postfixes, -to form a postfix expression. -It can also contain -another conditional compilation block, -or a combination of these expressions and blocks. +在`#if`、`#endif`和其他编译指令之间, +条件编译块可以包含 +一个隐式成员表达式, +后面可以跟零个或多个后缀, +以形成后缀表达式。 +它也可以包含 +另一个条件编译块, +或这些表达式和块的组合。 -You can use this syntax anywhere that you can write -an explicit member expression, -not just in top-level code. +您可以在任何可以编写 +显式成员表达式的 +地方使用这种语法,而不仅仅局限于顶层代码。 -In the conditional compilation block, -the branch for the `#if` compilation directive -must contain at least one expression. -The other branches can be empty. +在条件编译块中, +`#if`编译指令的分支 +必须至少包含一个表达式。 +其他分支可以留空 -> Grammar of an explicit member expression: +> 显式成员表达式的语法: > > *explicit-member-expression* → *postfix-expression* **`.`** *decimal-digits* \ > *explicit-member-expression* → *postfix-expression* **`.`** *identifier* *generic-argument-clause*_?_ \ @@ -3000,44 +2991,44 @@ The other branches can be empty. See grammar for initializer-expression for the related "argument name" production there. --> -### Postfix Self Expression +### 后缀自我表达 -A postfix `self` expression consists of an expression or the name of a type, -immediately followed by `.self`. It has the following forms: +后缀`self`表达式由表达式或类型名称组成, +后跟: ```swift <#expression#>.self <#type#>.self ``` -The first form evaluates to the value of the *expression*. -For example, `x.self` evaluates to `x`. +第一种形式计算表达式的值。 +例如,`x.self`计算为`x`。 -The second form evaluates to the value of the *type*. Use this form -to access a type as a value. For example, -because `SomeClass.self` evaluates to the `SomeClass` type itself, -you can pass it to a function or method that accepts a type-level argument. +第二种形式计算类型的值。使用这种形式 +可以访问类型作为值。例如, +因为`SomeClass.self`计算为`SomeClass`类型本身, +你可以将它传递给接受类型级参数的函数或方法。 -> Grammar of a postfix self expression: +> 后缀自我表达的语法: > > *postfix-self-expression* → *postfix-expression* **`.`** **`self`** -### Subscript Expression +### 下标表达式 -A *subscript expression* provides subscript access -using the getter and setter -of the corresponding subscript declaration. -It has the following form: +*下标表达式*通过 +相应的下标声明的getter和setter +提供下标访问。 +其形式如下: ```swift <#expression#>[<#index expressions#>] ``` -To evaluate the value of a subscript expression, -the subscript getter for the *expression*'s type is called -with the *index expressions* passed as the subscript parameters. -To set its value, -the subscript setter is called in the same way. +为了评估下标表达式的值, +调用下标获取器,获取*表达式*的类型, +并将*索引表达式*作为下标参数传递。 +为了设置其值, +以相同的方式调用下标设置器. -For information about subscript declarations, -see . +有关下标声明的信息, +请参阅 . -> Grammar of a subscript expression: +> 下标表达式的语法: > > *subscript-expression* → *postfix-expression* **`[`** *function-call-argument-list* **`]`** @@ -3076,25 +3067,25 @@ see . ``` --> -### Forced-Value Expression +### 强制值表达式 -A *forced-value expression* unwraps an optional value -that you are certain isn't `nil`. -It has the following form: +*强制值表达式*用于展开一个可选值, +您确定该值不是`null` +其形式如下: ```swift <#expression#>! ``` -If the value of the *expression* isn't `nil`, -the optional value is unwrapped -and returned with the corresponding non-optional type. -Otherwise, a runtime error is raised. +如果*表达式*的值不为`nil`, +则可选值将被解包 +并以相应的非可选类型返回。 +否则,将引发运行时错误。 -The unwrapped value of a forced-value expression can be modified, -either by mutating the value itself, -or by assigning to one of the value's members. -For example: +强制值表达式的解包值可以被修改, +通过改变值本身, +或通过赋值给值的某个成员。 +例如: ```swift var x: Int? = 0 @@ -3122,43 +3113,43 @@ someDictionary["a"]![0] = 100 ``` --> -> Grammar of a forced-value expression: +> 强制值表达式的语法: > > *forced-value-expression* → *postfix-expression* **`!`** -### Optional-Chaining Expression +### 可选链式表达式 -An *optional-chaining expression* provides a simplified syntax -for using optional values in postfix expressions. -It has the following form: +一个*可选链式表达式*提供了 +在后缀表达式中使用可选值的简化语法。 +它具有以下形式: ```swift <#expression#>? ``` -The postfix `?` operator makes an optional-chaining expression -from an expression without changing the expression's value. +后缀`?`运算符使一个可选链式表达式 +从一个表达式中产生,而不改变表达式的值。 -Optional-chaining expressions must appear within a postfix expression, -and they cause the postfix expression to be evaluated in a special way. -If the value of the optional-chaining expression is `nil`, -all of the other operations in the postfix expression are ignored -and the entire postfix expression evaluates to `nil`. -If the value of the optional-chaining expression isn't `nil`, -the value of the optional-chaining expression is unwrapped -and used to evaluate the rest of the postfix expression. -In either case, -the value of the postfix expression is still of an optional type. +可选链式表达式必须出现在后缀表达式中, +它们以特殊的方式导致后缀表达式的计算。 +如果可选链式表达式的值为`nil`, +后缀表达式中的所有其他操作将被忽略, +整个后缀表达式的计算结果为`nil`。 +如果可选链表达式的值不是`nil`, +则可选链表达式的值将被展开 +并用于计算后缀表达式的其余部分。 +无论哪种情况, +后缀表达式的值仍然是可选类型。 -If a postfix expression that contains an optional-chaining expression -is nested inside other postfix expressions, -only the outermost expression returns an optional type. -In the example below, -when `c` isn't `nil`, -its value is unwrapped and used to evaluate `.property`, -the value of which is used to evaluate `.performAction()`. -The entire expression `c?.property.performAction()` -has a value of an optional type. +如果包含可选链表达式的后缀表达式 +嵌套在其他后缀表达式中, +则只有最外层的表达式返回可选类型。 +在下面的例子中, +当`c`不为`nil`时, +其值被解包并用于计算`.property`, +而`.property`的值则用于计算`.performAction()`。 +整个表达式`c?.property.performAction()` +的值为可选类型 ```swift var c: SomeClass? @@ -3177,9 +3168,9 @@ var result: Bool? = c?.property.performAction() ``` --> -The following example shows the behavior -of the example above -without using optional chaining. +以下示例显示了 +上述示例 +在不使用可选链式操作时的行为. ```swift var result: Bool? @@ -3202,13 +3193,13 @@ if let unwrappedC = c { ``` --> -The unwrapped value of an optional-chaining expression can be modified, -either by mutating the value itself, -or by assigning to one of the value's members. -If the value of the optional-chaining expression is `nil`, -the expression on the right-hand side of the assignment operator -isn't evaluated. -For example: +可选链表达式的未包装值可以修改, +通过改变值本身, +或通过赋值给值的成员之一。 +如果可选链表达式的值为“nil”, +赋值运算符右侧的表达式 +将不会计算。 +例如: ```swift func someFunctionWithSideEffects() -> Int { @@ -3247,22 +3238,13 @@ someDictionary["a"]?[0] = someFunctionWithSideEffects() ``` --> -> Grammar of an optional-chaining expression: +> 选链式表达式的语法: > > *optional-chaining-expression* → *postfix-expression* **`?`** -> Beta Software: +> 测试版软件: > -> This documentation contains preliminary information about an API or technology in development. This information is subject to change, and software implemented according to this documentation should be tested with final operating system software. +> 本文件包含有关开发中的API或技术的初步信息。这些信息可能会发生变化,根据本文件实施的软件应与最终操作系统软件一起测试。. > -> Learn more about using [Apple's beta software](https://developer.apple.com/support/beta-software/). - - From 5076f672fef58ffbd6446f442f9a92ba3c752a40 Mon Sep 17 00:00:00 2001 From: king-open Date: Wed, 16 Oct 2024 01:41:58 +0800 Subject: [PATCH 03/14] =?UTF-8?q?=E7=BF=BB=E8=AF=91=E5=AE=8C=E8=BF=99?= =?UTF-8?q?=E7=AF=87=E6=96=87=E7=AB=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../ReferenceManual/Expressions.md | 1144 ++++------------- 1 file changed, 270 insertions(+), 874 deletions(-) diff --git a/swift-6-beta.docc/ReferenceManual/Expressions.md b/swift-6-beta.docc/ReferenceManual/Expressions.md index eab216153..5333fbdff 100644 --- a/swift-6-beta.docc/ReferenceManual/Expressions.md +++ b/swift-6-beta.docc/ReferenceManual/Expressions.md @@ -1,103 +1,73 @@ -# 表达 - -访问,修改和赋值. - -在Swift中,有四种表达式: -前缀表达式,中缀表达式,主表达式和后缀表达式 -计算表达式会返回一个值, -产生一个副作用,或同时产生这两个结果。 - -前缀和中间缀表达式允许您 -将运算符应用于更小的表达式。 -主表达式在概念上是最简单的表达式, -它们提供了一种访问值的方法。 -后缀表达式 -与前缀和中间缀表达式一样 -允许您使用后缀(如函数调用和成员访问) -构建更复杂的表达式。 -每种表达式都将在 -以下部分中详细描述。 - -> 表达语法: +# 表达式 + +访问、修改和分配值。 + +在 Swift 中,有四种表达式:前缀表达式、中缀表达式、主表达式和后缀表达式。计算表达式会返回一个值、导致副作用,或两者兼而有之。 + +前缀和中缀表达式允许您将运算符应用于较小的表达式。主表达式在概念上是最简单的表达式,它们提供了一种访问值的方法。后缀表达式与前缀和中缀表达式一样,允许您使用后缀构建更复杂的表达式,例如函数调用和成员访问。下面各节详细描述了每种表达式。 + +> 表达式的语法: > > *expression* → *try-operator*_?_ *await-operator*_?_ *prefix-expression* *infix-expressions*_?_ \ -## 前缀表达式 +## 前缀表达式 -*前缀表达式* 将 -可选的前缀运算符与表达式结合在一起。 -前缀运算符接受一个参数, -即紧随其后的表达式 +前缀表达式将可选的前缀运算符与表达式结合起来。前缀运算符采用一个参数,即它们后面的表达式。 -有关这些运营商行为的信息, -看 . +有关这些运算符的行为的信息,请参阅。 -有关Swift标准库提供的操作符的信息, -看[Operator Declarations](https://developer.apple.com/documentation/swift/operator_declarations). +有关 Swift 标准库提供的运算符的信息,请参阅[Operator Declarations](https://developer.apple.com/documentation/swift/operator_declarations)。 -> 前缀表达的语法: +> 前缀表达式的语法: > > *prefix-expression* → *prefix-operator*_?_ *postfix-expression* \ > *prefix-expression* → *in-out-expression* ### 输入输出表达式 -*输入输出表达式* 标记作为输入输出参数传递给函数调用表达式的变量. +输入输出表达式标记作为输入输出参数传递给函数调用表达式的变量。 ```swift &<#expression#> ``` -如需了解进出参数的更多信息并查看示例, -看 . +有关输入输出参数的更多信息以及查看示例,请参阅. -在需要指针的上下文中提供非指针参数时,也会使用输入输出表达式,如 . +在需要指针的上下文中提供非指针参数时,也会使用输入输出表达式,如 中所述。 -> 输入输出表达式的语法: +> 输入输出表达式的语法: > > *in-out-expression* → **`&`** *primary-expression* ### 尝试操作员 - *try 表达式* 由 try 操作符 -后跟一个可能引发错误的表达式组成。 -其格式如下: + try 表达式由`try` 运算符后跟一个可能引发错误的表达式组成。它具有以下形式: ```swift try <#expression#> ``` `try` 表达式的值是 *表达式*的值. -可选尝试表达式由`try?` 操作符 -后跟可能引发错误的表达式组成。 -其形式如下: +可选的 try 表达式由`try?` 组成。运算符后跟可能引发错误的表达式。它具有以下形式: ```swift try? <#expression#> ``` -如果 *表达式* 没有引发错误, -可选-尝试表达式的值 -是一个可选的,包含 *表达式的值* . -否则,可选-尝试表达式的值为`nil`. +如果表达式没有抛出错误,则可选尝试表达式的值是包含表达式值的可选值。否则,可选尝试表达式的值为 `nil`。 + +强制尝试表达式由`try!` 组成。运算符后跟可能引发错误的表达式。它具有以下形式: + -一个*强制-尝试表达式*由`try!`操作符 -后跟一个可能引发错误的表达式组成。 -它具有以下形式: ```swift try! <#expression#> ``` -强制尝试表达式的值就是*表达式的值。 -如果*表达式*抛出错误, -就会产生运行时错误。 +强制尝试表达式的值是表达式的值。如果表达式抛出错误,则会产生运行时错误。 -当中缀运算符左侧的表达式 -带有 `try`、`try?`或 `try!`标记时, -该运算符将应用于整个中缀表达式。 -也就是说,你可以使用括号来明确运算符的应用范围. +当中缀运算符左侧的表达式标有 `try` 时, `try?` ,或者 `try!` ,该运算符适用于整个中缀表达式。也就是说,您可以使用括号来明确运算符应用程序的范围。 ```swift // try applies to both function calls @@ -143,9 +113,7 @@ sum = (try someThrowingFunction()) + anotherThrowingFunction() ``` --> -`try`表达式不能出现在中缀运算符的右侧, -除非中缀运算符是赋值运算符, -或者`try`表达式被括在括号内 +`try` 表达式不能出现在中缀运算符的右侧,除非中缀运算符是赋值运算符或者 `try`表达式括在括号中。 -如果一个表达式同时包含`try`和`await`操作符, -则`try`操作符必须出现在前面。 +如果表达式同时包含`try`和`await`运算符,则`try`运算符必须首先出现。 -欲了解更多信息,并查看如何使用`try`、`try?`和`try!`的示例, -请参阅 . +有关更多信息并查看如何使用`try`、`try?`的示例,并 `try! ` 请参阅 . -> 尝试表达的语法: +> try 表达式的语法: > > *try-operator* → **`try`** | **`try`** **`?`** | **`try`** **`!`** -### 等待操作员 +### 等待接线员 -*等待表达式*由`await`操作符 -后跟使用异步操作结果的表达式组成. -其形式如下: +*wait* 表达式由`await`运算符后跟一个使用异步操作结果的表达式组成。它具有以下形式 ```swift await <#expression#> ``` -带有`await`的表达式称为*潜在暂停点*。 -异步函数的执行可以暂停 -在每个带有`await`的表达式。 -此外, -并发代码的执行永远不会暂停在任何其他点。 -这意味着潜在暂停点之间的代码 -可以安全地更新需要暂时打破不变量的状态, -前提是它完成更新 -在下一个潜在暂停点之前。 +`await`表达式的值是expression的值。标有await表达式称为 *潜在挂起点* 。异步函数的执行可以在每个用 `await`标记的表达式处暂停。此外,并发代码的执行永远不会在任何其他点暂停。这意味着潜在挂起点之间的代码可以安全地更新需要暂时破坏不变量的状态,前提是它在下一个潜在挂起点之前完成更新。 -`await` 表达式只能出现在异步上下文中, -例如传递给 `async(priority:operation:)` 函数的尾部闭包。 -它不能出现在 `defer` 语句的体内, -也不能出现在同步函数类型的自动闭包中。 -当中缀运算符左侧的表达式 -带有`await`运算符时, -该运算符将应用于整个中缀表达式。 -也就是说,你可以使用括号 -来明确运算符的应用范围。 + +`await` 表达式只能出现在异步上下文中,例如传递给 `async(priority:operation:)`函数的尾随闭包。它不能出现在defer语句的主体中,也不能出现在同步函数类型的自动闭包中。 + +当中缀运算符左侧的表达式用`await`运算符标记时,该运算符适用于整个中缀表达式。也就是说,您可以使用括号来明确运算符应用程序的范围。 ```swift // await applies to both function calls @@ -247,9 +198,7 @@ sum = (await someAsyncFunction()) + anotherAsyncFunction() ``` --> -`await`表达式不能出现在中缀运算符的右侧, -除非中缀运算符是赋值运算符, -或者”等待"表达式被括在括号内。 +`await`表达式不能出现在中缀运算符的右侧,除非中缀运算符是赋值运算符或者将await表达式括在括号中。 -如果一个表达式同时包含`await`和`try`操作符, -则`try`操作符必须放在前面. +如果表达式同时包含 `await`和try运算符,则try运算符必须首先出现。 -> 备注:解析时, -> 由中缀运算符组成的表达式用 -> 作为一张平面列表. -> 这个列表会变成一棵树 -> 通过应用运算符优先级. -> 例如,表达 `2 + 3 * 5` -> 最初被理解为五个项目的列表, -> `2`, `+`, `3`, `*`, 和 `5`. -> 这个过程将树木转化成 (2 + (3 * 5)). +> 注意:在解析时,由中缀运算符组成的表达式表示为平面列表。通过应用运算符优先级将该列表转换为树。例如,表达式2 + 3 * 5最初被理解为五个项目2 、 + 、 3 、 *和5的平面列表。此过程将其转换为树 (2 + (3 * 5))。 -> 中缀表达的语法: +> 中缀表达式的语法: > > *infix-expression* → *infix-operator* *prefix-expression* \ > *infix-expression* → *assignment-operator* *try-operator*_?_ *await-operator*_?_ *prefix-expression* \ @@ -325,25 +260,15 @@ sum = (await someAsyncFunction()) + anotherAsyncFunction() > *infix-expression* → *type-casting-operator* \ > *infix-expressions* → *infix-expression* *infix-expressions*_?_ -### 作业员 - -*赋值运算符*为给定的表达式设置新的值。 +### 赋值运算符 -其形式如下: +*赋值运算符* 为给定表达式设置新值。它具有以下形式: ```swift <#expression#> = <#value#> ``` -*表达式*的值 -由计算*值*得到的值确定。 -如果*表达式*是一个元组, -*value*必须是一个 -元素数量相同的元组 -(允许嵌套元组)。 -赋值从*value*的每个部分 -到*表达式*的对应部分。 -例如: +*表达式* 的值设置为通过计算*value* 获得的值。如果表达式是元组,则值必须是具有相同元素数量的元组。 (允许嵌套元组。)从值的每个部分到表达式的相应部分执行赋值。例如: ```swift (a, _, (b, c)) = ("test", 9.45, (12, 3)) @@ -361,45 +286,33 @@ sum = (await someAsyncFunction()) + anotherAsyncFunction() ``` --> -赋值运算符不返回任何值. +赋值运算符不返回任何值。 -> 赋值运算符的语法: +> 赋值运算符的语法: > -> *assignment-operator* → **`=`** +> *赋值运算符* → **`=`** ### 三元条件运算符 -*三元条件运算符* 根据条件值 -计算两个给定值之一。 -其形式如下: +*三元条件运算符*根据条件值计算两个给定值之一。它具有以下形式: ```swift <#condition#> ? <#expression used if true#> : <#expression used if false#> ``` -如果*条件*的值为`true`, -则条件运算符将计算第一个表达式 -并返回其值。 -否则,它将计算第二个表达式 -并返回其值。 -未使用的表达式将不进行计算 +如果*条件*计算结果为`true` ,则条件运算符计算第一个表达式并返回其值。否则,它计算第二个表达式并返回其值。不计算未使用的表达式。 -For an example that uses the ternary conditional operator, -see . +有关使用三元条件运算符的示例,请参阅文档: . -> 条件运算符的语法: +> 条件运算符的语法: > -> *conditional-operator* → **`?`** *expression* **`:`** +> *条件运算符* → **`?`** *表达* **`:`** -### 类型铸造操作员 +### 类型转换运算符 -有四种类型转换操作符: -`is`操作符、 -`as`操作符、 -`as?`操作符、 -以及`as!`操作符 +有四种类型转换运算符: `is`运算符、`as`运算符、`as?`运算符和`as!`操作员。 -它们具有以下形式: +它们具有以下形式: ```swift <#expression#> is <#type#> @@ -408,10 +321,7 @@ see . <#expression#> as! <#type#> ``` -`is`运算符在运行时检查*表达式* -是否可以转换为指定的*类型*。 -如果*表达式*可以转换为指定的*类型*,则返回`true`; -否则返回`false`. +`is`运算符在运行时检查表达式是否可以转换为指定类型。如果*表达式*可以转换为指定*类型*,则返回`true` ;否则,返回`false` 。 -当在编译时 -已知转换总是成功时, -`as` 运算符执行转换, -例如上转换或桥接。 -上转换允许您将表达式用作其类型超类型的实例, -而无需使用中间变量。 -以下方法等效: +当在编译时已知转换始终成功时,`as`运算符会执行转换,例如向上转换或桥接。向上转换允许您使用表达式作为其类型的超类型的实例,而无需使用中间变量。以下方法是等效的: ```swift func f(_ any: Any) { print("Function for Any") } @@ -486,49 +390,26 @@ f(x as Any) ``` --> -桥接功能允许您将Swift标准库类型 -(如String) -作为其对应的Foundation类型(如NSString) -使用,而无需创建新实例。 -有关桥接的更多信息, -请参阅[Working with Foundation Types](https://developer.apple.com/documentation/swift/imported_c_and_objective_c_apis/working_with_foundation_types). - -`as?` 运算符 -将 *表达式* -转换为指定的 *类型*。 -`as?` 运算符返回指定 *类型* 的可选值。 -在运行时,如果转换成功, -*表达式* 的值将被封装为可选值并返回; -否则,返回的值为 `nil`。 -如果转换为指定的 *类型* -保证失败或保证成功, -将引发编译时错误。 - -`as!` 运算符强制将 *expression* 转换为指定的 *type*。 -`as!` 运算符返回指定 *type* 的值,而非可选类型。 -如果转换失败,将引发运行时错误。 -`x as! T` 的行为与 `(x as? T)!` 的行为相同。 - -如需了解有关类型转换的更多信息 -并查看使用类型转换运算符的示例, -请参阅. - -> 类型转换运算符的语法: +桥接允许您使用`Swift` 标准库类型(例如String的表达式作为其相应的基础类型(例如NSString ,而无需创建新实例。有关桥接的更多信息,请参阅[Working with Foundation Types](https://developer.apple.com/documentation/swift/imported_c_and_objective_c_apis/working_with_foundation_types). + +`as?`运算符执行表达式到指定类型的条件转换。 `as?`运算符返回指定类型的可选值。在运行时,如果转换成功,则将表达式的值包装在可选值中并返回;否则,返回值为`nil` 。如果强制转换为指定类型肯定会失败或一定会成功,则会引发编译时错误。 + +`as!`运算符将表达式强制转换为指定类型。 `as!`运算符返回指定类型的值,而不是可选类型。如果转换失败,则会引发运行时错误。 `x as! T`与 `(x as? T)!` 。 + +有关类型转换的更多信息以及查看使用类型转换运算符的示例,请参阅. + +> 类型转换运算符的语法: > -> *type-casting-operator* → **`is`** *type* \ -> *type-casting-operator* → **`as`** *type* \ -> *type-casting-operator* → **`as`** **`?`** *type* \ -> *type-casting-operator* → **`as`** **`!`** *type* +> *类型转换运算符* → **`is`** *类型* \ +> *类型转换运算符* → **`as`** *类型* \ +> *类型转换运算符* → **`as`** **`?`** *类型* \ +> *类型转换运算符* → **`as`** **`!`** *类型* -## 主要表达方式 +## 主要表达 -*基本表达式* -是最基本的表达式。 -它们可以单独使用, -也可以与其他标记结合, -构成前缀表达式、中缀表达式和后缀表达式。 +*初级表达式*是最基本的表达式。它们可以单独用作表达式,也可以与其他标记组合以构成前缀表达式、中缀表达式和后缀表达式。 -> 初级表达语法: +> 基本表达式的语法: > > *primary-expression* → *identifier* *generic-argument-clause*_?_ \ > *primary-expression* → *literal-expression* \ @@ -558,12 +439,9 @@ f(x as Any) is a *type* identifier. --> -### 字面表达 +### 文字表达 -一个*字面表达式*由 -普通字面(如字符串或数字)、 -数组或字典字面、 -或游戏字面. +文字表达式由普通文字(例如字符串或数字)、数组或字典文字或游乐场文字组成 > Note: > Prior to Swift 5.9, @@ -595,21 +473,13 @@ f(x as Any) ``` --> -*数组字面量*是 -有序的数值集合。 -它具有以下形式: +*数组文字*是值的有序集合。它具有以下形式: ```swift [<#value 1#>, <#value 2#>, <#...#>] ``` -数组中的最后一个表达式后面可以跟一个可选的逗号。 -数组字面值的类型为`[T]`, -其中`T`是数组中表达式的类型。 -如果有多种类型的表达式, -`T`是它们最接近的公共超类型。 -空数组字面值用一对空 -方括号表示,可用于创建指定类型的空数组. +数组中的最后一个表达式后面可以跟一个可选的逗号。数组文字的值具有类型`[T]` ,其中T是其中表达式的类型。如果存在多种类型的表达式,则`T` 是它们最接近的公共超类型。空数组文字使用一对空方括号编写,可用于创建指定类型的空数组。 ```swift var emptyArray: [Double] = [] @@ -623,26 +493,13 @@ var emptyArray: [Double] = [] ``` --> -*字典字面意思*是 -一个无序的键值对集合。 -它具有以下形式: +*字典文字* 是键值对的无序集合。它具有以下形式: ```swift [<#key 1#>: <#value 1#>, <#key 2#>: <#value 2#>, <#...#>] ``` -字典中的最后一个表达式后面可以跟一个可选的逗号。 -字典字面值的类型为[键:值], -其中键是其键表达式的类型, -值是其值表达式的类型。 -如果有多种类型的表达式, -键和值是各自值的最接近的公共超类型。 - -空字典字面值用 -,放在一对括号(`[:]`)内, -以区别于空数组字面量。 -您可以使用空字典字面量创建 -具有指定键和值类型的. +字典中的最后一个表达式后面可以跟一个可选的逗号。字典文字的值具有类型`[Key: Value]` ,其中 `Key`是其键表达式的类型, `Value` 是其值表达式的类型。如果存在多种类型的表达式,则`Key`和`Value`是其各自值最接近的公共超类型。空字典文字被写为一对括号 `( [:] )` 内的冒号,以将其与空数组文字区分开。您可以使用空字典文字来创建指定键和值类型的空字典文字。 ```swift var emptyDictionary: [String: Double] = [:] @@ -656,17 +513,11 @@ var emptyDictionary: [String: Double] = [:] ``` --> -Xcode使用*playground literal* -在程序编辑器中创建 -颜色、文件或图像的交互式表示。 -Xcode之外的纯文本playground literal -使用特殊的文字语法表示。 +Xcode 使用 *Playground* 文字在程序编辑器中创建颜色、文件或图像的交互式表示。 Xcode 之外的纯文本 Playground 文字使用特殊的文字语法表示。 -有关在Xcode中使用playground literal的信息, -请参阅[Add a color, file, or image literal](https://help.apple.com/xcode/mac/current/#/dev4c60242fc) -在Xcode帮助中 +有关在 Xcode 中使用 Playground 文字的信息,请参阅 Xcode 帮助中[Add a color, file, or image literal](https://help.apple.com/xcode/mac/current/#/dev4c60242fc) -> 字面表达的语法: +> 文字表达式的语法: > > *literal-expression* → *literal* \ > *literal-expression* → *array-literal* | *dictionary-literal* | *playground-literal* @@ -685,9 +536,7 @@ Xcode之外的纯文本playground literal ### 自我表达 -`self` 表达是指对当前类型 -或类型实例的明确引用。 -它有以下几种形式: +`self`表达式是对当前类型或它所在类型的实例的显式引用。它有以下几种形式: ```swift self @@ -701,16 +550,9 @@ self.init(<#initializer arguments#>) TODO: Come back and explain the second to last form (i.e., self(arg: value)). --> -在初始化器、下标或实例方法中,`self` 指的是当前 -出现的类型实例。在类型方法中, -`self` 指的是当前出现的类型。 +在初始值设定项、下标或实例方法中, `self`指的是它出现的类型的当前实例。在类型方法中, `self`指的是它出现的当前类型。 -`self` 表达式用于在访问成员时指定作用域, -当作用域中存在 -另一个同名变量时, -例如函数参数, -提供消除歧义的功能。 -例如: +`self`表达式用于在访问成员时指定作用域,当作用域中存在另一个同名变量(例如函数参数)时,可以消除歧义。例如: ```swift class SomeClass { @@ -734,9 +576,7 @@ class SomeClass { ``` --> -在值类型的变体方法中, -您可以将值类型的新实例赋值给`self`。 -例如: +在值类型的变异方法中,您可以将该值类型的新实例分配给 `self` 。例如: ```swift struct Point { @@ -766,7 +606,7 @@ struct Point { -> 自我表达的语法: +> 自我表达的语法: > > *self-expression* → **`self`** | *self-method-expression* | *self-subscript-expression* | *self-initializer-expression* > @@ -774,11 +614,9 @@ struct Point { > *self-subscript-expression* → **`self`** **`[`** *function-call-argument-list* **`]`** \ > *self-initializer-expression* → **`self`** **`.`** **`init`** -### 超级表达 +### 超类表达式 -*超类表达式*允许类 -与其超类进行交互。 -它有以下几种形式: +*超类表达式*允许类与其超类交互。它具有以下形式之一: ```swift super.<#member name#> @@ -786,14 +624,11 @@ super[<#subscript index#>] super.init(<#initializer arguments#>) ``` -第一种形式用于访问超类的成员。 -第二种形式用于访问超类的下标实现。 -第三种形式用于访问超类的初始化器。 +第一种形式用于访问超类的成员。第二种形式用于访问超类的下标实现。第三种形式用于访问超类的初始值设定项。 -子类可以在成员、下标和初始化器的实现中使用超类表达式, -以利用其超类的实现. +子类可以在其成员、下标和初始化器的实现中使用超类表达式,以利用其超类中的实现。 -> 超级表达的语法: +> 超类表达式的语法: > > *superclass-expression* → *superclass-method-expression* | *superclass-subscript-expression* | *superclass-initializer-expression* > @@ -803,9 +638,7 @@ super.init(<#initializer arguments#>) ### 条件表达式 -一个*条件表达式*根据条件值计算出几个给定值中的一个. - -它有以下几种形式: +*条件表达式*根据条件值计算为多个给定值之一。它具有以下形式之一: ```swift if <#condition 1#> { @@ -826,53 +659,30 @@ default: } ``` -条件表达式 -的行为和语法与`if`语句或`switch`语句相同, -但以下段落描述的差异除外。 +除了以下段落描述的差异之外,条件表达式与`if`语句或`switch`语句具有相同的行为和语法。 -条件表达式仅出现在以下几种情况下: +条件表达式仅出现在以下上下文中: -- 作为赋给变量的值。 +- 作为分配给变量的值。 - 作为变量或常量声明中的初始值。 -- 作为`throw`表达式抛出的错误。 -- 作为函数、闭包或属性getter返回的值。 -- 作为条件表达式分支中的值。 +- 作为由 `throw `表达式引发的错​​误。 +- 作为函数、闭包或属性 `getter` 返回的值。 +- 作为条件表达式分支内的值。 -条件表达式的分支是穷举的, -确保表达式总是产生一个值, -无论条件如何。 -这意味着每个`if`分支都需要一个对应的`else`分支。 +条件表达式的分支是详尽的,确保无论条件如何,表达式始终生成一个值。这意味着每个if分支都需要一个相应的else分支。 -每个分支包含一个表达式, -当分支的条件为真时,该表达式用作条件表达式的值, +每个分支包含一个表达式(当该分支的条件为 true 时用作条件表达式的值)、一个 `throw`语句或对永不返回的函数的调用。 -一个`throw`语句, -或对从不返回的函数的调用。 - -每个分支必须产生相同类型的值。 -由于每个分支的类型检查都是独立的, -有时需要明确指定值的类型, -例如当分支包含不同类型的字面量时, -或者当分支的值为`nil`时。 -当需要提供此信息时, -请在结果被分配到的变量上添加类型注释, -或者在分支的值上添加`as`转换. +每个分支必须产生相同类型的值。由于每个分支的类型检查是独立的,因此有时需要显式指定值的类型,例如当分支包含不同类型的文字时,或者当分支的值为`nil`时。当您需要提供此信息时,请向结果分配到的变量添加类型注释,或向分支的值添加`as`强制转换。 ```swift let number: Double = if someCondition { 10 } else { 12.34 } let number = if someCondition { 10 as Double } else { 12.34 } ``` -在结果生成器中, -条件表达式只能 -作为变量或常量的初始值出现。 -这意味着,当您在结果生成器中编写`if`或`switch`语句时—— -在变量或常量声明之外—— -该代码将被视为分支语句, -结果生成器的某个方法将转换该代码。 +在结果生成器中,条件表达式只能显示为变量或常量的初始值。此行为意味着当您在结果生成器中编写`if`或`switch` 时(在变量或常量声明之外),该代码将被理解为分支语句,并且结果生成器的方法之一会转换该代码。 -不要在`try`表达式中放置条件表达式, -即使条件表达式的分支之一正在抛出异常。 +不要将条件表达式放入try表达式中,即使条件表达式的分支之一抛出异常。 > 条件句语法: > @@ -887,15 +697,9 @@ let number = if someCondition { 10 as Double } else { 12.34 } > *switch-expression-case* → *case-label* *statement* \ > *switch-expression-case* → *default-label* *statement* -### 结束语 表达 - -*闭包表达式*用于创建闭包, -在其他编程语言中也被称为*lambda*或*匿名函数*。 +### 闭包表达式 -与函数声明类似, -闭包包含语句, -并捕获其外围作用域中的常量和变量。 -其形式如下: +闭包表达式创建一个闭包,在其他编程语言中也称为*lambda*或匿名函数。与函数声明一样,闭包包含语句,并且它从其封闭范围捕获常量和变量。它具有以下形式: ```swift { (<#parameters#>) -> <#return type#> in @@ -903,12 +707,9 @@ let number = if someCondition { 10 as Double } else { 12.34 } } ``` -*参数*的形式 -与函数声明中的参数相同, -如 . +这些参数与函数声明中的参数具有相同的形式,如。 -在闭包表达式中写上`throws`或 `async`, -即可明确标记闭包为抛出或异步。 +在闭包表达式中写入`throws`或`async`显式地将闭包标记为抛出或异步。 ```swift { (<#parameters#>) async throws -> <#return type#> in @@ -916,35 +717,19 @@ let number = if someCondition { 10 as Double } else { 12.34 } } ``` -如果闭包的体包含一个`throws`语句或一个`try`表达式, -且该语句或表达式未嵌套在具有详尽错误处理的`do`语句中, -则该闭包被视为抛出。 -如果抛出闭包仅抛出一种类型的错误, -则该闭包被视为抛出该错误类型; -否则,则被视为抛出“任何错误”。 -同样,如果体包含一个`await`表达式, -则理解为异步。 +如果闭包的主体包含一个`throws`语句或一个未嵌套在具有详尽错误处理的`do`语句内的`try`表达式,则该闭包被理解为抛出。如果抛出闭包仅抛出单一类型的错误,则该闭包被理解为抛出该错误类型;否则,它被理解为抛出 `any Error` 。同样,如果主体包含`await`表达式,则它被理解为异步的。 -有几种特殊形式 -可以更简洁地编写闭包: +有几种特殊的形式可以让闭包写得更简洁: -- 闭包可以省略 -参数类型、返回类型或两者。 -如果省略了参数名称和两种类型, -请省略语句前的`in`关键字。 -如果省略的类型无法推断, -则会产生编译时错误。 -- 闭包可以省略参数名称。 -此时,参数的隐式命名 -为`$`后跟位置: -`$0`、`$1`、`$2`,以此类推。 -- 仅包含单个表达式的闭包 -会被理解为返回该表达式的值。 -在对周围表达式进行类型推断时,也会考虑该表达式的内容 +- 闭包可以省略其参数类型、返回类型或两者。如果省略参数名称和两种类型,请省略语句前的`in`关键字。如果无法推断省略的类型,则会引发编译时错误。 + +- 闭包可以省略其参数的名称。然后,其参数隐式命名为`$`后跟其位置: `$0` 、 `$1 ` 、 `$2`等。 -以下闭包表达式是等价的: +- 仅包含单个表达式的闭包被理解为返回该表达式的值。对周围表达式执行类型推断时,也会考虑该表达式的内容。 + +以下闭包表达式是等效的: ```swift myFunction { (x: Int, y: Int) -> Int in @@ -979,45 +764,19 @@ myFunction { $0 + $1 } ``` --> -有关将闭合传递给函数的更多信息, -请参阅 . +有关将闭包作为参数传递给函数的信息,请参阅 . -闭包表达式可以 -不存储在变量或常量中, -例如,当您立即将闭包用作函数调用的一部分时。 -在上述代码中传递给`myFunction`的闭包表达式是 -这种立即使用的示例。 -因此, -闭包表达式是转义还是非转义取决于 -表达式的上下文。 -如果立即调用 -或作为非转义函数参数传递。 -否则,闭包表达式为转义 -有关转义闭包的更多信息,请参阅. +闭包表达式可以在不存储在变量或常量中的情况下使用,例如当您立即使用闭包作为函数调用的一部分时。上面代码中传递给`myFunction`闭包表达式就是这种立即使用的示例。因此,闭包表达式是转义还是非转义取决于表达式的周围上下文。如果立即调用闭包表达式或作为非转义函数参数传递,则闭包表达式是非转义的。否则,闭包表达式就会转义。 -#### 捕捉列表 +有关转义闭包的更多信息,请参阅文档:. -默认情况下,闭包表达式捕获 -其周围作用域中的常量和变量, -并对这些值进行强引用。 -您可以使用*捕获列表*来明确控制 -闭包中如何捕获值。 +#### 捕获列表 -捕获列表以逗号分隔的表达式列表的形式书写, -用方括号括起来, -放在参数列表之前。 -如果使用捕获列表,则必须同时使用`in`关键字, -即使省略了参数名称、参数类型和返回类型。 +默认情况下,闭包表达式从其周围范围捕获常量和变量,并对这些值进行强引用。您可以使用捕获列表来显式控制如何在闭包中捕获值。 -捕获列表中的条目在 -创建闭包时初始化。 -对于捕获列表中的每个条目, -一个常量被初始化为 -周围作用域中具有相同名称的常量或变量的值。 +捕获列表写为以逗号分隔的表达式列表,并用方括号括起来,位于参数列表之前。如果使用捕获列表,则即使省略参数名称、参数类型和返回类型,也必须使用`in`关键字。 -例如,在下面的代码中, -`a`包含在捕获列表中,但`b`没有, -这导致它们的行为不同。 +捕获列表中的条目在创建闭包时被初始化。对于捕获列表中的每个条目,常量被初始化为周围范围中具有相同名称的常量或变量的值。例如,在下面的代码中, `a`包含在捕获列表中,但`b`不包含在捕获列表中,这使它们具有不同的行为。 ```swift var a = 0 @@ -1049,20 +808,7 @@ closure() ``` --> -有两个不同的东西名为`a`, -一个是周围作用域中的变量, -一个是闭包作用域中的常量, -但只有一个变量名为`b`。 -当闭包创建时,内部作用域中的`a` -使用外部作用域中`a`的值进行初始化, -但它们的值没有以特殊方式连接。 -这意味着外部作用域中`a`的值发生变化 -不会影响内部作用域中`a`的值, -也不会影响闭包内部`a`的值。 - -相反,只有一个名为`b`的变量—— -外部作用域中的`b`—— -因此,闭包内部或外部所做的更改在两个地方都可见。 +有两种不同的东西,名为`a` ,周围作用域中的变量和闭包作用域中的常量,但只有一个名为`b` 变量。创建闭包时,内部作用域中的`a`会使用外部作用域中a的值进行初始化,但它们的值不会以任何特殊方式连接。这意味着外部作用域中a值的更改不会影响内部作用域中`a`的值,闭包内部a的更改也不会影响闭包外部a的值。相比之下,只有一个名为b的变量——外部作用域中的`b`因此来自闭包内部或外部的更改在两个地方都可见。 -当捕获的变量的类型具有引用语义时,这种区别是不可见的。 - -例如, -在下面的代码中,有两个名为`x`的东西, -一个是外层作用域中的变量,一个是内层作用域中的常量, -但它们都引用同一个对象, -因为引用语义 +当捕获的变量的类型具有引用语义时,这种区别不可见。例如,下面的代码中有两个名为`x`的东西,外部作用域中的变量和内部作用域中的常量,但由于引用语义,它们都引用同一个对象。 ```swift class SimpleClass { @@ -1150,10 +890,7 @@ closure() ``` --> -如果表达式值的类型是类, -则可以在捕获列表中用 -`weak`或`unowned`标记表达式,以捕获 -对表达式值的弱引用或非自有引用。. +如果表达式值的类型是类,则可以使用`weak`或`unowned`标记捕获列表中的表达式,以捕获对该表达式值的弱或无主引用。 ```swift myFunction { print(self.title) } // implicit strong capture @@ -1183,11 +920,7 @@ myFunction { [unowned self] in print(self.title) } // unowned capture ``` --> -您还可以将任意表达式 -绑定到捕获列表中的命名值。 -表达式将在创建闭包时进行求值, -并以指定的强度捕获值。 -例如: +您还可以将任意表达式绑定到捕获列表中的命名值。创建闭包时将对表达式求值,并以指定的强度捕获该值。例如: ```swift // Weak capture of "self.parent" as "parent" @@ -1211,10 +944,8 @@ myFunction { [weak parent = self.parent] in print(parent!.title) } ``` --> -欲了解更多关于结束语的表达方式和示例, -请参阅 . -如需了解更多信息以及捕获列表示例, -请参阅. +有关闭包表达式的更多信息和示例,请参阅文档: . +关捕获列表的更多信息和示例,请参阅文档:. -> 封闭表达的语法: +> 闭包表达式的语法: > > *closure-expression* → **`{`** *attributes*_?_ *closure-signature*_?_ *statements*_?_ **`}`** > @@ -1257,12 +988,7 @@ myFunction { [weak parent = self.parent] in print(parent!.title) } ### 隐式成员表达式 -*隐式成员表达式* -是一种访问类型成员的简写方式, -例如枚举情况或类型方法, -在类型推断 -可以确定隐式类型的情况下。 -它具有以下形式: +*隐式成员*表达式是在类型推断可以确定隐含类型的上下文中访问类型成员(例如枚举情况或类型方法)的缩写方式。它具有以下形式: ```swift .<#member name#> @@ -1285,8 +1011,7 @@ x = .anotherValue ``` --> -如果推断的类型是可选的, -你也可以在隐式成员表达式中使用非可选类型的成员. +如果推断类型是可选类型,则还可以在隐式成员表达式中使用非可选类型的成员。 ```swift var someOptional: MyEnumeration? = .someValue @@ -1300,20 +1025,7 @@ var someOptional: MyEnumeration? = .someValue ``` --> -隐式成员表达式后面可以跟 -后缀运算符或《指南》中列出的其他后缀语法 -. -这被称为“链式隐式成员表达式”。 -虽然所有链式后缀表达式通常 -具有相同的类型, -但唯一的要求是整个链式隐式成员表达式 -必须能够转换为其上下文隐含的类型。 -具体来说, -如果隐含类型是可选的, -则可以使用非可选类型的值, -如果隐含类型是类类型, -则可以使用其子类之一的值。 -例如: +隐式成员表达式后面可以跟后缀运算符或中列出的其他后缀语法。这称为*链式隐式成员表达式*。尽管所有链接的后缀表达式都具有相同的类型是很常见的,但唯一的要求是整个链接的隐式成员表达式需要可转换为其上下文隐含的类型。具体来说,如果隐含类型是可选类型,则可以使用非可选类型的值,如果隐含类型是类类型,则可以使用其子类之一的值。例如: ```swift class SomeClass { @@ -1351,12 +1063,9 @@ let z: SomeClass = .sharedSubclass ``` --> -在上面的代码中, -`x`的类型与其上下文隐含的类型完全匹配, -`y`的类型可以从`SomeClass`转换为`SomeClass?`, -而`z`的类型可以从`SomeSubclass`转换为`SomeClass`。 +在上面的代码中, `x` 的类型与其上下文隐含的类型完全匹配, `y` 的类型可以从 `SomeClass` 转换为 `SomeClass?` ,并且 `z` 的类型可以从 `SomeSubclass` 转换为 `SomeClass` 。 -> 隐式成员表达式的语法: +> 隐式成员表达式的语法: > > *implicit-member-expression* → **`.`** *identifier* \ > *implicit-member-expression* → **`.`** *identifier* **`.`** *postfix-expression* @@ -1402,43 +1111,25 @@ let z: SomeClass = .sharedSubclass ### 带括号的表达式 -A带*括号的表达式*由 -带括号的表达式组成。 -您可以使用括号来明确分组表达式, -从而指定运算的优先级。 -括号分组不会改变表达式的类型—— -例如,(1)的类型就是Int。 +带括号的表达式由括号包围的表达式组成。您可以使用括号通过显式分组表达式来指定运算的优先级。分组括号不会更改表达式的类型 --- 例如, `(1)` 的类型只是 `Int` -> 带括号的表达式的语法: +> 括号表达式的语法 > > *parenthesized-expression* → **`(`** *expression* **`)`** ### 元组表达式 -一个*元组表达式*由 -一组用逗号分隔的表达式组成,并用括号括起来。 -每个表达式前都可以有一个可选的标识符, -用冒号(`:`)隔开。 -其格式如下: +*元组表达式*由逗号分隔的表达式列表组成,并用括号括起来。每个表达式前面可以有一个可选标识符,用冒号 (`:`) 分隔。它具有以下形式: ```swift (<#identifier 1#>: <#expression 1#>, <#identifier 2#>: <#expression 2#>, <#...#>) ``` -元组表达式中的每个标识符在 -元组表达式的范围内必须是唯一的。 -在嵌套元组表达式中, -同一嵌套级别的标识符必须是唯一的。 -例如, -`(a: 10, a: 20)` 是无效的, -因为标签 `a` 在同一级别出现了两次。 -然而,`(a: 10, b: (a: 1, x: 2))`是有效的—— -尽管`a`出现了两次, -但一次出现在外层元组中,一次出现在内层元组中。 +元组表达式中的每个标识符在元组表达式的范围内必须是唯一的。在嵌套元组表达式中,同一嵌套级别的标识符必须是唯一的。例如, `(a: 10, a: 20)` 是无效的,因为标签 `a` 在同一级别出现了两次。然而, `(a: 10, b: (a: 1, x: 2))` 是有效的——虽然 `a`出现了两次,但它在外元组中出现一次,在内元组中出现一次。 -一个元组表达式可以包含零个表达式, -也可以包含两个或更多表达式。 -括号内的单个表达式是一个带括号的表达式。 +元组表达式可以包含零个表达式,也可以包含两个或多个表达式。括号内的单个表达式是括号表达式。 -> 注意:在Swift中,空元组表达式和空元组类型 -> 都写成`()`。 -> 因为`Void`是`()`的类型别名, -> 所以可以用它来表示空元组类型。 -> 然而,像所有类型别名一样,`Void`始终是一个类型—— -> 不能用它来表示空元组表达式。 +> 注意:Swift 中空元组表达式和空元组类型都写成 `()` 。因为 `Void` 是 `()` 的类型别名,所以您可以使用它来编写空元组类型。然而,像所有类型别名一样, `Void` 始终是一种类型——您不能使用它来编写空元组表达式。 -> 元组表达式的语法: +> 元组表达式的语法: > > *tuple-expression* → **`(`** **`)`** | **`(`** *tuple-element* **`,`** *tuple-element-list* **`)`** \ > *tuple-element-list* → *tuple-element* | *tuple-element* **`,`** *tuple-element-list* \ @@ -1471,10 +1155,9 @@ A带*括号的表达式*由 ### 通配符表达式 -*通配符表达式* -用于在赋值期间明确忽略某个值。 -例如,在以下赋值中 -10被赋给`x`,而20被忽略: +*通配符表达式* 用于在赋值期间显式忽略某个值。例如,在以下赋值中,`10` 被分配给x ,20 被忽略: + + ```swift (x, _) = (10, 20) @@ -1495,106 +1178,59 @@ A带*括号的表达式*由 > > *wildcard-expression* → **`_`** -### 宏扩展表达式 +### 宏展开表达式 -*宏扩展表达式*由宏名称 -后跟以逗号分隔的宏参数列表(括号内)组成。 -宏在编译时扩展。 -宏扩展表达式具有以下形式: +*宏扩展表达式* 由宏名称和后跟括号中的以逗号分隔的宏参数列表组成。宏在编译时展开。宏展开表达式具有以下形式: ```swift <#macro name#>(<#macro argument 1#>, <#macro argument 2#>) ``` -宏扩展表达式省略了宏名称后的括号, -如果宏不接收任何参数。 - -宏扩展表达式不能作为参数的默认值出现, -Swift标准库中的[`file()`][]和[`line()`][]宏除外。 -当用作函数或方法参数的默认值时, -这些宏的计算使用调用位置的源代码位置, -而不是它们在函数定义中的位置. +宏扩展表达式不能作为参数的默认值出现,除了 Swift 标准库中的 `file()` 和 `line()` 宏。当用作函数或方法参数的默认值时,这些宏将使用调用站点的源代码位置(而不是它们在函数定义中出现的位置)进行计算。 [`file()`]: https://developer.apple.com/documentation/swift/file() [`line()`]: https://developer.apple.com/documentation/swift/line() -使用宏表达式调用独立宏。 -要调用附加宏, -请使用自定义属性语法,如 . -独立宏和附加宏的扩展方式如下: +您可以使用宏表达式来调用独立宏。要调用附加的宏,请使用 中描述的自定义属性语法。独立宏和附加宏都扩展如下: + -1. Swift解析源代码 -以生成抽象语法树(AST)。 +1. Swift 解析源代码以生成抽象语法树(AST)。 -2. 宏执行将AST节点作为输入 -并执行该宏所需的转换。 +2. 宏实现接收 AST 节点作为其输入并执行该宏所需的转换。 -3. 宏执行生成的转换后的AST节点 -将添加到原始的AST中。 +3. 宏实现生成的转换后的 AST 节点将添加到原始 AST 中。 -每个宏的扩展都是独立且自包含的。 -然而,作为性能优化, -Swift可能会启动一个外部进程来执行宏, -并重复使用相同的进程来扩展多个宏。 -当您执行宏时, -该代码不能依赖于您的代码之前扩展的宏, -或任何其他外部状态,如当前时间。 +每个宏的扩展都是独立且自成体系的。但是,作为性能优化,Swift 可能会启动一个实现宏的外部进程,并重用同一进程来扩展多个宏。当您实现宏时,该代码不得依赖于您的代码之前扩展的宏,或任何其他外部状态(例如当前时间)。 -对于具有多重作用的嵌套宏和附加宏, -扩展过程会重复进行。 -嵌套宏扩展表达式从外向内扩展。 -例如,在以下代码中 -`outerMacro(_:)`首先扩展,而未扩展的`innerMacro(_:)`调用 -出现在抽象语法树中, -作为输入传递给`outerMacro(_:)` +对于具有多个角色的嵌套宏和附加宏,会重复展开过程。嵌套宏展开表达式从外向内展开。例如,在下面的代码中, `outerMacro(_:) `首先展开,未展开的对`innerMacro(_:)`调用出现在 `outerMacro(_:)`接收的抽象语法树中。输入 ```swift #outerMacro(12, #innerMacro(34), "some text") ``` -一个具有多种作用的附加宏会为每个作用扩展一次。 -每次扩展都会收到相同的原始抽象语法树作为输入。 -Swift通过收集所有生成的抽象语法树节点 -并将其放置在抽象语法树中的相应位置 -来形成整体扩展. +具有多个角色的附加宏将为每个角色扩展一次。每个扩展都接收相同的原始 AST 作为其输入。 Swift 通过收集所有生成的 AST 节点并将它们放在 AST 中相应的位置来形成整体扩展。 -有关Swift宏的概述,请参阅 . +有关 Swift 中宏的概述,请参阅 . -> 宏扩展表达式的语法: +> 宏展开表达式的语法: > > *macro-expansion-expression* → **`#`** *identifier* *generic-argument-clause*_?_ *function-call-argument-clause*_?_ *trailing-closures*_?_ -### 关键路径表达式 +### 键路径表达式 -*键路径表达式* -是指一个类型的属性或下标。 -您可以在动态编程任务中使用键路径表达式, -例如键值观察。 -它们具有以下形式: +*键路径表达式*指的是类型的属性或下标。您可以在动态编程任务中使用键路径表达式,例如键值观察。它们具有以下形式: ```swift \<#type name#>.<#path#> ``` -*类型名称*是具体类型的名称, -包括任何通用参数, -例如`String`、`[Int]`或`Set`。 +*类型名称*是具体类型的名称,包括任何泛型参数,例如 `String` 、 `[Int]` 或 `Set` 。 -*路径*由 -属性名称、下标、可选链式表达式和 -强制解包表达式组成。 -这些关键路径组件中的每一个 -都可以根据需要重复任意次数, -且顺序不限。 +该*路径*由属性名称、下标、可选链表达式和强制展开表达式组成。这些关键路径组件中的每一个都可以根据需要以任何顺序重复多次。 -在编译时,关键路径表达式 -会被替换为 - [`KeyPath`](https://developer.apple.com/documentation/swift/keypath) 类 +在编译时,键路径表达式被[`KeyPath`](https://developer.apple.com/documentation/swift/keypath) 类的实例替换。 -要使用键路径访问一个值, -请将键路径传递给`下标(keyPath:)`下标, -该下标适用于所有类型。 -例如: +要使用键路径访问值,请将键路径传递给 `subscript(keyPath:)` 下标,该下标适用于所有类型。例如: -在类型推断 -可以确定隐含类型的情况下,可以省略 -类型名称。 -以下代码使用`\.someProperty` -代替`\SomeClass.someProperty` : +在类型推断可以确定隐含类型的上下文中,可以省略类型名称。以下代码使用 `\.someProperty` 而不是 `\SomeClass.someProperty` : ```swift class SomeClass: NSObject { @@ -1677,14 +1309,7 @@ c.observe(\.someProperty) { object, change in Tracking bug is --> -*路径*可以包含多个属性名称, -以句点分隔, -以引用属性值的属性。 -此代码使用关键路径表达式 -`\OuterStructure.outer.someValue` -来访问 -`OuterStructure`类型`outer`属性的 -`someValue`属性: +该*路径* 可以引用self来创建身份密钥路径 `( \.self )`。身份键路径引用整个实例,因此您可以使用它一步来访问和更改存储在变量中的所有数据。例如: ```swift var compoundValue = (a: 1, b: 2) @@ -1702,14 +1327,7 @@ compoundValue[keyPath: \.self] = (a: 10, b: 20) ``` --> -*路径*可以包含多个属性名称, -以句点分隔, -以引用属性值的属性。 -此代码使用关键路径表达式 -`\OuterStructure.outer.someValue` -来访问 -`OuterStructure`类型`outer`属性的 -`someValue`属性: +该路径可以包含多个属性名称,以句点分隔,以引用属性值的属性。此代码使用关键路径表达式 `\OuterStructure.outer.someValue` 访问 `OuterStructure` 类型的 `outer` 属性的 `someValue` 属性: ```swift struct OuterStructure { @@ -1746,10 +1364,7 @@ let nestedValue = nested[keyPath: nestedKeyPath] ``` --> -*路径*可以使用括号包含下标, -只要下标的参数类型符合可哈希(Hashable)协议即可。 -本例在键路径中使用下标 -来访问数组的第二个元素: +*路径*可以包含使用括号的下标,只要下标的参数类型符合 `Hashable` 协议即可。此示例使用键路径中的下标来访问数组的第二个元素: ```swift let greetings = ["hello", "hola", "bonjour", "안녕"] @@ -1775,14 +1390,7 @@ let myGreeting = greetings[keyPath: \[String].[1]] [SR-5865]: Key path expression is "ambiguous without more context" --> -下标中使用的值可以是命名值或文字。 -使用值语义在键路径中捕获值。 -以下代码在键路径表达式和闭包中均使用变量`index` -来访问 -`greetings`数组的第三个元素。 -当修改`index`时, -键路径表达式仍引用第三个元素, -而闭包使用新的索引. +下标中使用的值可以是命名值或文字。使用值语义在关键路径中捕获值。以下代码在键路径表达式和闭包中使用变量 `index` 来访问 `greetings` 数组的第三个元素。当 `index` 被修改时,键路径表达式仍然引用第三个元素,而闭包使用新索引。 ```swift var index = 2 @@ -1828,8 +1436,7 @@ print(fn(greetings)) ``` --> -*路径*可以使用可选链和强制解包。 -这段代码在键: +该路径可以使用可选链接和强制展开。此代码在键路径中使用可选链接来访问可选字符串的属性: ```swift let firstGreeting: String? = greetings.first @@ -1862,11 +1469,7 @@ print(count as Any) Swift 5.2 regression in keypaths --> -您可以混合和匹配关键路径的组件,以访问 -嵌套在类型中的 -值。以下代码通过组合这些组件的关键路径表达式 -访问数组字典 -的不同值和属性. +您可以混合和匹配关键路径的组件来访问深度嵌套在类型中的值。以下代码通过使用组合这些组件的键路径表达式来访问数组字典的不同值和属性。 ```swift let interestingNumbers = ["prime": [2, 3, 5, 7, 11, 13, 17], @@ -1900,14 +1503,7 @@ print(interestingNumbers[keyPath: \[String: [Int]].["hexagonal"]!.count.bitWidth ``` --> -您可以在通常提供函数或闭包的上下文中使用键路径表达式。 - -具体来说, -您可以使用 -根类型为 `SomeType` -且路径生成`Value`类型值的 -键路径表达式, -而不是`(SomeType) -> Value`类型的函数或闭包. +您可以在通常提供函数或闭包的上下文中使用键路径表达式。具体来说,您可以使用根类型为 `SomeType` 且其路径生成 `Value` 类型的值的键路径表达式,而不是 `(SomeType) -> Value` 类型的函数或闭包。 ```swift struct Task { @@ -1952,12 +1548,7 @@ let descriptions2 = toDoList.filter { $0.completed }.map { $0.description } "The Pirates Who Don't Do Anything". --> -关键路径表达式的任何副作用 -仅在表达式被评估时进行评估。 -例如, -如果您在关键路径表达式中的下标内进行函数调用, -则该函数仅在评估表达式时调用一次, -而不是在每次使用关键路径时调用. +关键路径表达式的任何副作用仅在计算表达式的点进行计算。例如,如果您在关键路径表达式的下标内进行函数调用,则该函数仅在计算表达式时调用一次,而不是每次使用关键路径时都被调用。 ```swift func makeIndex() -> Int { @@ -1991,11 +1582,8 @@ let someTask = toDoList[keyPath: taskKeyPath] ``` --> -如需了解有关在 -与Objective-C API交互的代码中使用关键路径的更多信息, -请参阅 [Using Objective-C Runtime Features in Swift](https://developer.apple.com/documentation/swift/using_objective_c_runtime_features_in_swift). -有关键值编码和键值观察的信息, -请参阅[Key-Value Coding Programming Guide](https://developer.apple.com/library/content/documentation/Cocoa/Conceptual/KeyValueCoding/index.html#//apple_ref/doc/uid/10000107i) +有关在与 Objective-C API 交互的代码中使用关键路径的更多信息,请参阅 [Using Objective-C Runtime Features in Swift](https://developer.apple.com/documentation/swift/using_objective_c_runtime_features_in_swift). +有关键值编码和键值观察的信息,请参阅[Key-Value Coding Programming Guide](https://developer.apple.com/library/content/documentation/Cocoa/Conceptual/KeyValueCoding/index.html#//apple_ref/doc/uid/10000107i) 和 [Key-Value Observing Programming Guide](https://developer.apple.com/library/content/documentation/Cocoa/Conceptual/KeyValueObserving/KeyValueObserving.html#//apple_ref/doc/uid/10000177i). > 键路径表达式的语法: @@ -2007,12 +1595,9 @@ let someTask = toDoList[keyPath: taskKeyPath] > *key-path-postfixes* → *key-path-postfix* *key-path-postfixes*_?_ \ > *key-path-postfix* → **`?`** | **`!`** | **`self`** | **`[`** *function-call-argument-list* **`]`** -### 选择器 表达 +### 选择器表达式 -选择器表达式允许您访问 -Objective-C中用于引用方法或属性 -getter或setter的选择器。 -其格式如下: +选择器表达式允许您访问用于引用 Objective-C 中的方法或属性的 getter 或 setter 的选择器。它具有以下形式: ```swift #selector(<#method name#>) @@ -2020,10 +1605,7 @@ getter或setter的选择器。 #selector(setter: <#property name#>) ``` -*方法名*和*属性名*必须引用 -Objective-C运行时中可用 -的某个方法或属性。选择器表达式的值是`Selector`类型的实例。 -例如: +方法名称和属性名称必须是对 Objective-C 运行时中可用的方法或属性的引用。选择器表达式的值是 `Selector` 类型的实例。例如: ```swift class SomeClass: NSObject { @@ -2060,15 +1642,9 @@ let selectorForPropertyGetter = #selector(getter: SomeClass.property) ``` --> -在为属性的getter创建选择器时, -*属性名称*可以是指向变量或常量属性的引用。 -相反,在为属性的setter创建选择器时, -*属性名称*必须仅是指向变量属性的引用。 +为属性的 getter 创建选择器时,*属性名称*可以是对变量或常量属性的引用。相反,当为属性的设置器创建选择器时,*属性名称* 必须仅是对变量属性的引用。 -*方法名称*可以包含用于分组的括号, -以及用于区分同名但类型不同的方法的`as`运算符 - -例如: +*方法名称*可以包含用于分组的括号,以及用于消除共享名称但具有不同类型签名的方法之间的歧义的 `as`运算符。例如: ```swift extension SomeClass { @@ -2099,18 +1675,13 @@ let anotherSelector = #selector(SomeClass.doSomething(_:) as (SomeClass) -> (Str ``` --> -因为选择器是在编译时创建的,而不是在运行时创建的, -编译器可以检查方法或属性是否存在 -以及它们是否暴露给Objective-C运行时. +因为选择器是在编译时创建的,而不是在运行时创建的,所以编译器可以检查方法或属性是否存在以及它们是否暴露给 Objective-C 运行时。 -> Note: Although the *method name* and the *property name* are expressions, -> they're never evaluated. +> 注意:虽然*方法名称*和*属性名称*是表达式,但它们永远不会被求值 -如需了解如何使用选择器 -在Swift代码中与Objective-C API交互, -请参阅[Using Objective-C Runtime Features in Swift](https://developer.apple.com/documentation/swift/using_objective_c_runtime_features_in_swift). +有关在与 Objective-C API 交互的 Swift 代码中使用选择器的更多信息,请参阅[Using Objective-C Runtime Features in Swift](https://developer.apple.com/documentation/swift/using_objective_c_runtime_features_in_swift). -> Grammar of a selector expression: +> 选择器表达式的语法: > > *selector-expression* → **`#selector`** **`(`** *expression* **`)`** \ > *selector-expression* → **`#selector`** **`(`** **`getter:`** *expression* **`)`** \ @@ -2125,19 +1696,13 @@ let anotherSelector = #selector(SomeClass.doSomething(_:) as (SomeClass) -> (Str ### 键路径字符串表达式 -键路径字符串表达式允许您访问 -用于在Objective-C中引用属性的字符串, -用于键值编码和键值观察API。 -其格式如下: +键路径字符串表达式允许您访问用于引用 Objective-C 中的属性的字符串,以用于键值编码和键值观察 API。它具有以下形式: ```swift #keyPath(<#property name#>) ``` -*属性名称*必须引用 -Objective-C运行时中可用的 -属性。在编译时,键路径字符串表达式将被替换为字符串字面量。 -例如: +*属性名称*必须是对 Objective-C 运行时中可用的属性的引用。在编译时,键路径字符串表达式被替换为字符串文字。例如: ```swift class SomeClass: NSObject { @@ -2178,9 +1743,7 @@ if let value = c.value(forKey: keyPath) { ``` --> -当您在类中使用键路径字符串表达式时, -只需写上属性名称即可引用该类的属性, -而无需写上类名称 +当您在类中使用键路径字符串表达式时,您可以通过仅编写属性名称而不编写类名称来引用该类的属性。 ```swift extension SomeClass { @@ -2206,35 +1769,25 @@ print(keyPath == c.getSomeKeyPath()) ``` --> -因为键路径字符串是在编译时创建的,而不是在运行时创建的, -编译器可以检查属性是否存在 -以及该属性是否暴露给Objective-C运行时。 +由于关键路径字符串是在编译时而不是运行时创建的,因此编译器可以检查该属性是否存在以及该属性是否公开给 Objective-C 运行时。 -如需了解如何使用 -Swift代码中的关键路径与Objective-C API交互, -请参阅[Using Objective-C Runtime Features in Swift](https://developer.apple.com/documentation/swift/using_objective_c_runtime_features_in_swift). -有关键值编码和键值观察的信息, -请参阅 [Key-Value Coding Programming Guide](https://developer.apple.com/library/content/documentation/Cocoa/Conceptual/KeyValueCoding/index.html#//apple_ref/doc/uid/10000107i) -和 [Key-Value Observing Programming Guide](https://developer.apple.com/library/content/documentation/Cocoa/Conceptual/KeyValueObserving/KeyValueObserving.html#//apple_ref/doc/uid/10000177i). +有关在与 Objective-C API 交互的 Swift 代码中使用关键路径的更多信息,请参阅[Using Objective-C Runtime Features in Swift](https://developer.apple.com/documentation/swift/using_objective_c_runtime_features_in_swift)。 +有关键值编码和键值观察的信息,请参阅 [Key-Value Coding Programming Guide](https://developer.apple.com/library/content/documentation/Cocoa/Conceptual/KeyValueCoding/index.html#//apple_ref/doc/uid/10000107i) +和 [Key-Value Observing Programming Guide](https://developer.apple.com/library/content/documentation/Cocoa/Conceptual/KeyValueObserving/KeyValueObserving.html#//apple_ref/doc/uid/10000177i)。 -> Note: Although the *property name* is an expression, it's never evaluated. +> 注意:虽然*属性名称*是一个表达式,但它永远不会被计算。 -> Grammar of a key-path string expression: +> 键路径字符串表达式的语法: > -> *key-path-string-expression* → **`#keyPath`** **`(`** *expression* **`)`** +> *键路径字符串表达式* → **`#keyPath`** **`(`** *表达式* **`)`** ## 后缀表达式 -*后缀表达式*是通过 -将后缀运算符或其他后缀语法 -应用到表达式来形成的。 -从语法上讲,每个主要表达式也是后缀表达式。 +*后缀表达式*是通过对表达式应用后缀运算符或其他后缀语法来形成的。从语法上来说,每个主表达式也是一个后缀表达式。 -有关这些运算符的行为, -请参阅 and . +有关这些运算符的行为的信息,请参阅。 -有关Swift标准库提供的操作符的信息, -请参阅[Operator Declarations](https://developer.apple.com/documentation/swift/operator_declarations). +有关 Swift 标准库提供的运算符的信息,请参阅[Operator Declarations](https://developer.apple.com/documentation/swift/operator_declarations)。 > 后缀表达式的语法: > @@ -2255,33 +1808,22 @@ Swift代码中的关键路径与Objective-C API交互, revisit this section to make sure that the names for things match. --> -*函数调用表达式*由函数名称 -后跟以逗号分隔的函数参数列表组成,参数列表放在括号内。 -函数调用表达式具有以下形式: +函数调用*表达式*由函数名称和后跟括号中的以逗号分隔的函数参数列表组成。函数调用表达式具有以下形式: ```swift <#function name#>(<#argument value 1#>, <#argument value 2#>) ``` -*函数名称*可以是任何表达式,其值是函数类型。 +*函数名称*可函数名可以是任何其值是函数类型的表达式。 -如果函数定义包括其参数的名称, -则函数调用必须在参数值之前包含名称, -并用冒号(`:`)分隔。 +如果函数定义包含其参数名称,则函数调用必须在其参数值之前包含名称,并用冒号(`:`)分隔。 这种函数调用表达式具有以下形式: ```swift <#function name#>(<#argument name 1#>: <#argument value 1#>, <#argument name 2#>: <#argument value 2#>) ``` -函数调用表达式可以包含 -紧接在右括号之后的闭包表达式形式的尾部闭包。 -尾部闭包被理解为函数的参数, -添加在最后一个带括号的参数之后。 -第一个闭包表达式没有标签; -任何附加的闭包表达式前面都有其参数标签。 -下面的示例显示了 -使用和不使用尾部闭包语法的函数调用的等效版本: +函数调用表达式可以在紧跟在右括号之后以闭包表达式的形式包含尾随闭包。尾随闭包被理解为函数的参数,添加在最后一个带括号的参数之后。第一个闭包表达式是无标签的;任何其他闭包表达式前面都有其参数标签。下面的示例显示了使用和不使用尾随闭包语法的函数调用的等效版本: ```swift // someFunction takes an integer and a closure as its arguments @@ -2329,8 +1871,7 @@ anotherFunction(x: x) { $0 == 13 } g: { print(99) } Tracking bug is --> -如果尾随闭合是该函数的唯一参数, -则可以省略括号. +如果尾随闭包是函数的唯一参数,则可以省略括号。 ```swift // someMethod takes a closure as its only argument @@ -2364,46 +1905,25 @@ myData.someMethod { $0 == 13 } Tracking bug is --> -为了在参数中包含尾部闭合, -编译器从左到右检查函数的参数,如下所示: +为了在参数中包含尾随闭包,编译器从左到右检查函数的参数,如下所示: -| 尾随关闭 | 参数 | 行为 | +| 尾随闭包 | 范围 | 行动 | | ---------------- | --------- | ------ | -| 贴标签 | 贴标签| 如果标签相同,则封口与参数匹配; 否则,参数将被跳过. | -| 有标签 | 无标签 | 跳过参数 | -| 无标签 | 有标签或无标签 | 如果参数在结构上类似于如下定义的函数类型,则闭包与参数匹配;否则,跳过该参数. | - -尾随闭包作为参数传递给它匹配的参数。 -在扫描过程中跳过的参数 -没有传递给它们的参数 --- -例如,它们可以使用默认参数。 -找到匹配项后,扫描继续 -下一个尾随闭包和下一个参数。 -在匹配过程结束时, -所有尾随闭包都必须有匹配项。 - -如果参数不是输入输出参数,则该参数在结构上与函数类型 -类似, -且该参数属于以下类型之一: - -- 类型为函数类型的参数, -如 `(Bool) -> Int` -- 自动闭包参数, -其包装表达式的类型为函数类型, -如 `@autoclosure () -> ((Bool) -> Int)` -- 可变参数, -其数组元素类型为函数类型, -如 `((Bool) -> Int)...` -- 类型被一层或多层可选包装的参数, -如 `Optional<(Bool) -> Int>` -- 参数类型结合了这些允许的类型, -如 `(Optional<(Bool) -> Int>)...` - -当尾随闭包与参数匹配时, -其类型在结构上类似于函数类型,但不是函数, -则根据需要包装闭包。 -例如,如果参数的类型是可选类型, -则自动将闭包包装在 `Optional` 中. +| 贴上标签 | 贴上标签 | 如果标签相同,则闭包与参数匹配;否则,该参数将被跳过。| +| 贴上标签 | 未标记 | 该参数被跳过。 | +| 未标记 | 有标签或无标签 | 如果参数在结构上类似于函数类型(如下定义),则闭包与参数匹配;否则,该参数将被跳过。 | + +尾随闭包作为其匹配参数的参数传递。在扫描过程中跳过的参数没有传递给它们的参数——例如,它们可以使用默认参数。找到匹配项后,将继续扫描下一个尾随闭包和下一个参数。在匹配过程结束时,所有尾随闭包都必须有匹配项。 + +如果参数不是输入输出参数,并且参数是以下之一,则该参数在结构上类似于函数类型: + +- 类型为函数类型的参数,如`(Bool) -> Int` +- 一个自动闭包参数,其包装表达式的类型是函数类型,例如 `@autoclosure () -> ((Bool) -> Int)` +- 数组元素类型为函数类型的可变参数,例如`((Bool) -> Int)...` +- 其类型被包裹在一层或多层可选中的参数,例如`Optional<(Bool) -> Int>` +- 其类型组合了这些允许类型的参数,例如 `(Optional<(Bool) -> Int>)...` + +当尾随闭包与结构上类似于函数类型但不是函数的参数匹配时,闭包将根据需要进行包装。例如,如果参数的类型是可选类型,则闭包会自动包装在 `Optional` 中. -为了简化从Swift 5.3之前的版本迁移代码的过程—— -该版本从右向左进行匹配—— -编译器会同时检查从左向右和从右向左的顺序。 -如果扫描方向产生不同的结果, -则使用旧的从右向左顺序, -编译器会生成警告。 -未来的Swift版本将始终使用从左向右的顺序. +为了简化从 5.3 之前的 Swift 版本(执行从右到左的匹配)的代码迁移,编译器会检查从左到右和从右到左的顺序。如果扫描方向产生不同的结果,则使用旧的从右到左排序,并且编译器会生成警告。 Swift 的未来版本将始终使用从左到右的排序。 ```swift typealias Callback = (Int) -> Int @@ -2480,27 +1994,18 @@ someFunction { return $0 } secondClosure: { return $0 } // Prints "10 20" ``` --> -在上面的例子中, -标记为'Ambiguous'的函数调用 -在Swift 5.3上打印“- 120”并产生编译器警告。 -未来版本的Swift将打印'110 -'. +在上面的示例中,标记为“Ambigitude”的函数调用会打印“- 120”,并在 Swift 5.3 上生成编译器警告。 Swift 的未来版本将打印“110 -”。 -类、结构或枚举类型 -可通过声明多种方法之一, -为函数调用语法提供语法糖, -如 . +类、结构或枚举类型可以通过声明多种方法之一来启用函数调用语法的语法糖,如 中所述。 #### 隐式转换为指针类型 -在函数调用表达式中, -如果参数和参数的类型不同, -编译器会尝试通过 -应用以下列表中的隐式转换之一来使它们的类型匹配: +在函数调用表达式中,如果参数和参数具有不同的类型,编译器会尝试通过应用以下列表中的隐式转换之一来使它们的类型匹配: - `inout SomeType` 可以成为 `UnsafePointer` 或 `UnsafeMutablePointer` @@ -2509,7 +2014,7 @@ someFunction { return $0 } secondClosure: { return $0 } // Prints "10 20" - `Array`可以成为`UnsafePointer` - `String`可以成为`UnsafePointer` -以下两个函数调用是等价的: +以下两个函数调用是等效的: ```swift func unsafeFunction(pointer: UnsafePointer) { @@ -2538,27 +2043,11 @@ withUnsafePointer(to: myNumber) { unsafeFunction(pointer: $0) } ``` --> -这些隐式转换创建的指针 -仅在函数调用期间有效。 -为避免出现未定义行为, -请确保您的代码 -在函数调用结束后不会保留指针. +通过这些隐式转换创建的指针仅在函数调用期间有效。为了避免未定义的行为,请确保您的代码在函数调用结束后永远不会保留指针。 -> Note: When implicitly converting an array to an unsafe pointer, -> Swift ensures that the array's storage is contiguous -> by converting or copying the array as needed. -> For example, you can use this syntax -> with an array that was bridged to `Array` -> from an `NSArray` subclass that makes no API contract about its storage. -> If you need to guarantee that the array's storage is already contiguous, -> so the implicit conversion never needs to do this work, -> use `ContiguousArray` instead of `Array`. +> 当将数组隐式转换为不安全指针时,Swift 通过根据需要转换或复制数组来确保数组的存储是连续的。例如,您可以将此语法与从 `NSArray` 子类桥接到 `Array` 的数组一起使用,该子类不对其存储制定任何 API 约定。如果您需要保证数组的存储已经是连续的,因此隐式转换永远不需要执行此工作,请使用 `ContiguousArray` 而不是 `Array` 。 -使用`&`代替`withUnsafePointer(to:)`等显式函数 -有助于提高低级C函数调用的可读性, -尤其是当函数需要多个指针参数时。 -然而,当从其他Swift代码调用函数时, -应避免使用`&`代替显式使用不安全的API. +使用`&`而不是像`withUnsafePointer(to:)`这样的显式函数可以帮助提高对低级 C 函数的调用的可读性,特别是当函数采用多个指针参数时。但是,当从其他 Swift 代码调用函数时,请避免使用`&`而应显式使用不安全的 API。 -> 函数调用表达式的语法: +> 函数调用表达式的语法: > > *function-call-expression* → *postfix-expression* *function-call-argument-clause* \ > *function-call-expression* → *postfix-expression* *function-call-argument-clause*_?_ *trailing-closures* @@ -2620,18 +2109,13 @@ withUnsafePointer(to: myNumber) { unsafeFunction(pointer: $0) } ### 初始化表达式 -*初始化表达式*用于访问 -类型的初始化器。 -其形式如下: +初始值设定项表达式提供对类型的初始值设定项的访问。它具有以下形式: ```swift <#expression#>.init(<#initializer arguments#>) ``` -在函数调用表达式中使用初始化表达式 -来初始化一个类型的新实例。 -还可以使用初始化表达式 -来委托给超类的初始化器. +您可以在函数调用表达式中使用初始化表达式来初始化类型的新实例。您还可以使用初始值设定项表达式来委托给超类的初始值设定项。 ```swift class SomeSubClass: SomeSuperClass { @@ -2656,8 +2140,7 @@ class SomeSubClass: SomeSuperClass { ``` --> -初始化器可以像函数一样用作值。 -例如: +与函数一样,初始化器可以用作值。例如: ```swift // Type annotation is required because String has multiple initializers. @@ -2679,9 +2162,7 @@ print(oneTwoThree) ``` --> -如果您指定了类型名称, -则无需使用初始化表达式即可访问该类型的初始化程序。 -在其他情况下,您必须使用初始化表达式. +如果按名称指定类型,则可以访问该类型的初始值设定项,而无需使用初始值设定项表达式。在所有其他情况下,您必须使用初始化表达式。 ```swift let s1 = SomeType.init(data: 3) // Valid @@ -2711,25 +2192,20 @@ let s4 = type(of: someValue)(data: 5) // Error ``` --> -> 初始化表达式的语法: +> 初始化表达式的语法: > > *initializer-expression* → *postfix-expression* **`.`** **`init`** \ > *initializer-expression* → *postfix-expression* **`.`** **`init`** **`(`** *argument-names* **`)`** -### 明确的会员表达 +### 显式成员表达式 -*显式成员表达式*允许访问 -已命名类型、元组或模块的成员。 -它由句点(`.`)分隔, -位于项目与其成员标识符之间. +*显式成员表达式*允许访问命名类型、元组或模块的成员。它由项目与其成员标识符之间的句点 ( `.` ) 组成。 ```swift <#expression#>.<#member name#> ``` -命名类型的成员在 -类型声明或扩展中命名。 -例如: +命名类型的成员被命名为类型声明或扩展的一部分。例如: ```swift class SomeClass { @@ -2751,10 +2227,7 @@ let y = c.someProperty // Member access ``` --> -元组的成员 -按出现顺序用整数隐式命名, -从0开始。 -例如: +元组的成员按照它们出现的顺序使用整数隐式命名,从零开始。例如: ```swift var t = (10, 20, 30) @@ -2772,21 +2245,13 @@ t.0 = t.1 ``` --> -模块的成员可以访问 -该模块的顶层声明。 +模块的成员访问该模块的顶级声明。 -使用`dynamicMemberLookup`属性声明的类型 -包括在运行时查找的成员, -如 . +使用`dynamicMemberLookup`属性声明的类型包括在运行时查找的成员,如 中所述。 为了区分名称仅因参数名称而不同的方法或初始化器, -请将参数名称放在括号内, -每个参数名称后加一个冒号(`:`)。 -对于没有名称的参数,请写一个下划线(`_`)。 -为了区分重载方法, -请使用类型注释。 -例如: +要区分名称仅因参数名称不同的方法或初始值设定项,请将参数名称包含在括号中,每个参数名称后跟一个冒号 `:` )。为没有名称的参数写入下划线 ( `_` )。要区分重载方法,请使用类型注释。例如: ```swift class SomeClass { @@ -2853,11 +2318,7 @@ let d: (Int, Bool) -> Void = instance.overloadedMethod(x:y:) // Unambiguous ``` --> -如果一行开头出现句点, -则应理解为显式成员表达式的一部分, -而非隐式成员表达式。 -例如,以下列表显示了 -分几行显示的链式方法调用: +如果句点出现在行的开头,则它将被理解为显式成员表达式的一部分,而不是隐式成员表达式。例如,以下清单显示了分为几行的链式方法调用: ```swift let x = [10, 3, 20, 15, 4] @@ -2879,11 +2340,7 @@ let x = [10, 3, 20, 15, 4] ``` --> -您可以将这种多行链式语法 -与编译器控制语句 -相结合,以控制每个方法的调用时间。 -例如, -以下代码在iOS上使用不同的过滤规则: +您可以将此多行链式语法与编译器控制语句结合起来,以控制每个方法的调用时间。例如,以下代码在 iOS 上使用不同的过滤规则: ```swift let numbers = [10, 20, 33, 43, 50] @@ -2909,23 +2366,11 @@ let numbers = [10, 20, 33, 43, 50] ``` --> -在`#if`、`#endif`和其他编译指令之间, -条件编译块可以包含 -一个隐式成员表达式, -后面可以跟零个或多个后缀, -以形成后缀表达式。 -它也可以包含 -另一个条件编译块, -或这些表达式和块的组合。 +在 `#if` 、 `#endif`和其他编译指令之间,条件编译块可以包含隐式成员表达式,后跟零个或多个后缀,以形成后缀表达式。它还可以包含另一个条件编译块,或这些表达式和块的组合。 -您可以在任何可以编写 -显式成员表达式的 -地方使用这种语法,而不仅仅局限于顶层代码。 +您可以在任何可以编写显式成员表达式的地方使用此语法,而不仅仅是在顶级代码中。 -在条件编译块中, -`#if`编译指令的分支 -必须至少包含一个表达式。 -其他分支可以留空 +在条件编译块中, `#if` 编译指令的分支必须至少包含一个表达式。其他分支可以为空。 -### 后缀自我表达 +### 自我表达 -后缀`self`表达式由表达式或类型名称组成, -后跟: +后缀`self` 表达式由表达式或类型名称组成,后跟 `.self` 。它有以下几种形式: ```swift <#expression#>.self <#type#>.self ``` -第一种形式计算表达式的值。 -例如,`x.self`计算为`x`。 +第一种形式计算表达式的值。例如, `x.self` 计算结果为 `x` 。 -第二种形式计算类型的值。使用这种形式 -可以访问类型作为值。例如, -因为`SomeClass.self`计算为`SomeClass`类型本身, -你可以将它传递给接受类型级参数的函数或方法。 +第二种形式求值为*type*的值。使用此形式将类型作为值进行访问。例如,由于 `SomeClass.self` 计算结果为 `SomeClass` 类型本身,因此您可以将其传递给接受类型级参数的函数或方法。 > 后缀自我表达的语法: > @@ -3015,20 +2455,13 @@ let numbers = [10, 20, 33, 43, 50] ### 下标表达式 -*下标表达式*通过 -相应的下标声明的getter和setter -提供下标访问。 -其形式如下: +*下标表达式*使用相应下标声明的 getter 和 setter 提供下标访问。它具有以下形式: ```swift <#expression#>[<#index expressions#>] ``` -为了评估下标表达式的值, -调用下标获取器,获取*表达式*的类型, -并将*索引表达式*作为下标参数传递。 -为了设置其值, -以相同的方式调用下标设置器. +为了计算下标表达式的值,需要调用表达式类型的下标 getter,并将索引表达式作为下标参数传递。为了设置它的值,以同样的方式调用下标设置器。 -有关下标声明的信息, -请参阅 . +有关下标声明的信息,请参阅 . > 下标表达式的语法: > @@ -3067,25 +2499,17 @@ let numbers = [10, 20, 33, 43, 50] ``` --> -### 强制值表达式 +### 强制值表达 -*强制值表达式*用于展开一个可选值, -您确定该值不是`null` -其形式如下: +*强制值表达式*会解包您确定不是 `nil` 的可选值。它具有以下形式: ```swift <#expression#>! ``` -如果*表达式*的值不为`nil`, -则可选值将被解包 -并以相应的非可选类型返回。 -否则,将引发运行时错误。 +如果表达式的值不是 `nil` ,则可选值将被解包并以相应的非可选类型返回。否则,会引发运行时错误。 -强制值表达式的解包值可以被修改, -通过改变值本身, -或通过赋值给值的某个成员。 -例如: +可以通过改变值本身或分配给值的成员之一来修改强制值表达式的展开值。例如: ```swift var x: Int? = 0 @@ -3115,41 +2539,21 @@ someDictionary["a"]![0] = 100 > 强制值表达式的语法: > -> *forced-value-expression* → *postfix-expression* **`!`** +> *强制值表达式* → *后缀表达式* **`!`** ### 可选链式表达式 -一个*可选链式表达式*提供了 -在后缀表达式中使用可选值的简化语法。 -它具有以下形式: +*可选链表达式*提供了在后缀表达式中使用可选值的简化语法。它具有以下形式: ```swift <#expression#>? ``` -后缀`?`运算符使一个可选链式表达式 -从一个表达式中产生,而不改变表达式的值。 +后缀 `?` 运算符从表达式创建可选链表达式而不更改表达式的值。 -可选链式表达式必须出现在后缀表达式中, -它们以特殊的方式导致后缀表达式的计算。 -如果可选链式表达式的值为`nil`, -后缀表达式中的所有其他操作将被忽略, -整个后缀表达式的计算结果为`nil`。 -如果可选链表达式的值不是`nil`, -则可选链表达式的值将被展开 -并用于计算后缀表达式的其余部分。 -无论哪种情况, -后缀表达式的值仍然是可选类型。 +可选链表达式必须出现在后缀表达式中,并且它们会导致后缀表达式以特殊方式进行计算。如果可选链表达式的值为 `nil` ,则后缀表达式中的所有其他操作都将被忽略,并且整个后缀表达式的计算结果为 `nil` 。如果可选链表达式的值不是 `nil` ,则可选链表达式的值将被展开并用于计算后缀表达式的其余部分。无论哪种情况,后缀表达式的值仍然是可选类型。 -如果包含可选链表达式的后缀表达式 -嵌套在其他后缀表达式中, -则只有最外层的表达式返回可选类型。 -在下面的例子中, -当`c`不为`nil`时, -其值被解包并用于计算`.property`, -而`.property`的值则用于计算`.performAction()`。 -整个表达式`c?.property.performAction()` -的值为可选类型 +如果包含可选链表达式的后缀表达式嵌套在其他后缀表达式中,则只有最外面的表达式返回可选类型。在下面的示例中,当 `c `不为 `nil`时,其值将被展开并用于计算 `.property` ,其值用于计算 `.performAction()` 。整个表达式 `c?.property.performAction()`具有可选类型的值。 ```swift var c: SomeClass? @@ -3168,9 +2572,7 @@ var result: Bool? = c?.property.performAction() ``` --> -以下示例显示了 -上述示例 -在不使用可选链式操作时的行为. +以下示例显示了上面示例的行为,而不使用可选链。 ```swift var result: Bool? @@ -3193,13 +2595,7 @@ if let unwrappedC = c { ``` --> -可选链表达式的未包装值可以修改, -通过改变值本身, -或通过赋值给值的成员之一。 -如果可选链表达式的值为“nil”, -赋值运算符右侧的表达式 -将不会计算。 -例如: +可以通过改变值本身或分配给值的成员之一来修改可选链表达式的展开值。如果可选链表达式的值为nil ,则不计算赋值运算符右侧的表达式。例如: ```swift func someFunctionWithSideEffects() -> Int { @@ -3238,13 +2634,13 @@ someDictionary["a"]?[0] = someFunctionWithSideEffects() ``` --> -> 选链式表达式的语法: +> 可选链表达式的语法: > > *optional-chaining-expression* → *postfix-expression* **`?`** > 测试版软件: > -> 本文件包含有关开发中的API或技术的初步信息。这些信息可能会发生变化,根据本文件实施的软件应与最终操作系统软件一起测试。. +> 本文档包含有关正在开发的 API 或技术的初步信息。该信息可能会发生变化,并且根据本文档实现的软件应使用最终操作系统软件进行测试。. > > 了解更多关于使用 [Apple's beta software](https://developer.apple.com/support/beta-software/). From cd75a42e3700d15bb796a6585b9cfb16e399afe7 Mon Sep 17 00:00:00 2001 From: King <66349714+king-open@users.noreply.github.com> Date: Wed, 16 Oct 2024 01:46:10 +0800 Subject: [PATCH 04/14] Update Expressions.md --- swift-6-beta.docc/ReferenceManual/Expressions.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/swift-6-beta.docc/ReferenceManual/Expressions.md b/swift-6-beta.docc/ReferenceManual/Expressions.md index 5333fbdff..567fba6bd 100644 --- a/swift-6-beta.docc/ReferenceManual/Expressions.md +++ b/swift-6-beta.docc/ReferenceManual/Expressions.md @@ -2640,7 +2640,7 @@ someDictionary["a"]?[0] = someFunctionWithSideEffects() > 测试版软件: > -> 本文档包含有关正在开发的 API 或技术的初步信息。该信息可能会发生变化,并且根据本文档实现的软件应使用最终操作系统软件进行测试。. +> 本文件包含有关开发中的API或技术的初步信息。这些信息可能会发生变化,根据本文件实施的软件应与最终操作系统软件一起测试。. > > 了解更多关于使用 [Apple's beta software](https://developer.apple.com/support/beta-software/). From 08d11eb03ac14ab0672db90304c3e351429a4b39 Mon Sep 17 00:00:00 2001 From: Frank Chu <38122319+yongfrank@users.noreply.github.com> Date: Wed, 16 Oct 2024 18:44:40 +0800 Subject: [PATCH 05/14] Update swift-6-beta.docc/ReferenceManual/Patterns.md --- swift-6-beta.docc/ReferenceManual/Patterns.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/swift-6-beta.docc/ReferenceManual/Patterns.md b/swift-6-beta.docc/ReferenceManual/Patterns.md index af852e87b..74fd4f208 100644 --- a/swift-6-beta.docc/ReferenceManual/Patterns.md +++ b/swift-6-beta.docc/ReferenceManual/Patterns.md @@ -1,4 +1,4 @@ -# 图案 +# 模式 匹配和解构值. From 81cae2496d0e3470fdc73c55f5cd32693cec1906 Mon Sep 17 00:00:00 2001 From: Frank Chu <38122319+yongfrank@users.noreply.github.com> Date: Sat, 19 Oct 2024 23:11:47 +0800 Subject: [PATCH 06/14] Update Expressions.md --- swift-6-beta.docc/ReferenceManual/Expressions.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/swift-6-beta.docc/ReferenceManual/Expressions.md b/swift-6-beta.docc/ReferenceManual/Expressions.md index 567fba6bd..83e268d89 100644 --- a/swift-6-beta.docc/ReferenceManual/Expressions.md +++ b/swift-6-beta.docc/ReferenceManual/Expressions.md @@ -39,7 +39,7 @@ > > *in-out-expression* → **`&`** *primary-expression* -### 尝试操作员 +### Try 运算符 try 表达式由`try` 运算符后跟一个可能引发错误的表达式组成。它具有以下形式: From 19087d6ead63cd027da159172602d8e2b31f56d8 Mon Sep 17 00:00:00 2001 From: King <66349714+king-open@users.noreply.github.com> Date: Sat, 19 Oct 2024 23:14:45 +0800 Subject: [PATCH 07/14] Up: Expressions.md --- swift-6-beta.docc/ReferenceManual/Expressions.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/swift-6-beta.docc/ReferenceManual/Expressions.md b/swift-6-beta.docc/ReferenceManual/Expressions.md index 83e268d89..5333fbdff 100644 --- a/swift-6-beta.docc/ReferenceManual/Expressions.md +++ b/swift-6-beta.docc/ReferenceManual/Expressions.md @@ -39,7 +39,7 @@ > > *in-out-expression* → **`&`** *primary-expression* -### Try 运算符 +### 尝试操作员 try 表达式由`try` 运算符后跟一个可能引发错误的表达式组成。它具有以下形式: @@ -2640,7 +2640,7 @@ someDictionary["a"]?[0] = someFunctionWithSideEffects() > 测试版软件: > -> 本文件包含有关开发中的API或技术的初步信息。这些信息可能会发生变化,根据本文件实施的软件应与最终操作系统软件一起测试。. +> 本文档包含有关正在开发的 API 或技术的初步信息。该信息可能会发生变化,并且根据本文档实现的软件应使用最终操作系统软件进行测试。. > > 了解更多关于使用 [Apple's beta software](https://developer.apple.com/support/beta-software/). From 055aae6698e2357ac8a73232662b156804119c44 Mon Sep 17 00:00:00 2001 From: King <66349714+king-open@users.noreply.github.com> Date: Sat, 19 Oct 2024 23:20:01 +0800 Subject: [PATCH 08/14] =?UTF-8?q?=E9=87=8D=E6=96=B0=E7=BF=BB=E8=AF=91?= =?UTF-8?q?=E4=BA=86=E8=BF=99=E7=AF=87=E6=96=87=E7=AB=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit From fdc66f707f953ee9477393b1ccd0baf99cc6fa31 Mon Sep 17 00:00:00 2001 From: King <66349714+king-open@users.noreply.github.com> Date: Sat, 19 Oct 2024 23:30:46 +0800 Subject: [PATCH 09/14] =?UTF-8?q?=E9=87=8D=E6=96=B0=E7=BF=BB=E8=AF=91?= =?UTF-8?q?=E4=BA=86=E8=BF=99=E7=AF=87=E6=96=87=E7=AB=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- swift-6-beta.docc/ReferenceManual/Patterns.md | 2717 +++++++++++++++-- 1 file changed, 2475 insertions(+), 242 deletions(-) diff --git a/swift-6-beta.docc/ReferenceManual/Patterns.md b/swift-6-beta.docc/ReferenceManual/Patterns.md index 74fd4f208..5333fbdff 100644 --- a/swift-6-beta.docc/ReferenceManual/Patterns.md +++ b/swift-6-beta.docc/ReferenceManual/Patterns.md @@ -1,413 +1,2646 @@ -# 模式 +# 表达式 -匹配和解构值. +访问、修改和分配值。 -*模式* 表示单个值或复合值的结构。例如,元组`(1, 2)` 的结构是两个元素的逗号分隔列表。由于模式代表值的结构而不是任何一个特定值,因此您可以将它们与多种值进行匹配。例如,模式 `(x, y)`与元组 `(1, 2)` 和任何其他二元素元组匹配。除了将模式与值进行匹配之外,您还可以提取复合值的部分或全部并将每个部分绑定到常量或变量名称。 +在 Swift 中,有四种表达式:前缀表达式、中缀表达式、主表达式和后缀表达式。计算表达式会返回一个值、导致副作用,或两者兼而有之。 -在 Swift 中,有两种基本类型的模式:那些成功匹配任何类型值的模式,以及那些在运行时可能无法匹配指定值的模式。 +前缀和中缀表达式允许您将运算符应用于较小的表达式。主表达式在概念上是最简单的表达式,它们提供了一种访问值的方法。后缀表达式与前缀和中缀表达式一样,允许您使用后缀构建更复杂的表达式,例如函数调用和成员访问。下面各节详细描述了每种表达式。 -第一种模式用于解构简单变量、常量和可选绑定中的值。其中包括通配符模式、标识符模式以及包含它们的任何值绑定或元组模式。您可以为这些模式指定类型注释,以限制它们仅匹配特定类型的值。 +> 表达式的语法: +> +> *expression* → *try-operator*_?_ *await-operator*_?_ *prefix-expression* *infix-expressions*_?_ \ + +## 前缀表达式 + +前缀表达式将可选的前缀运算符与表达式结合起来。前缀运算符采用一个参数,即它们后面的表达式。 + +有关这些运算符的行为的信息,请参阅。 + +有关 Swift 标准库提供的运算符的信息,请参阅[Operator Declarations](https://developer.apple.com/documentation/swift/operator_declarations)。 + +> 前缀表达式的语法: +> +> *prefix-expression* → *prefix-operator*_?_ *postfix-expression* \ +> *prefix-expression* → *in-out-expression* + +### 输入输出表达式 + +输入输出表达式标记作为输入输出参数传递给函数调用表达式的变量。 + +```swift +&<#expression#> +``` + +有关输入输出参数的更多信息以及查看示例,请参阅. + +在需要指针的上下文中提供非指针参数时,也会使用输入输出表达式,如 中所述。 + +> 输入输出表达式的语法: +> +> *in-out-expression* → **`&`** *primary-expression* + +### 尝试操作员 + + try 表达式由`try` 运算符后跟一个可能引发错误的表达式组成。它具有以下形式: + +```swift +try <#expression#> +``` +`try` 表达式的值是 *表达式*的值. + +可选的 try 表达式由`try?` 组成。运算符后跟可能引发错误的表达式。它具有以下形式: + + +```swift +try? <#expression#> +``` + +如果表达式没有抛出错误,则可选尝试表达式的值是包含表达式值的可选值。否则,可选尝试表达式的值为 `nil`。 + +强制尝试表达式由`try!` 组成。运算符后跟可能引发错误的表达式。它具有以下形式: + + + +```swift +try! <#expression#> +``` + +强制尝试表达式的值是表达式的值。如果表达式抛出错误,则会产生运行时错误。 + +当中缀运算符左侧的表达式标有 `try` 时, `try?` ,或者 `try!` ,该运算符适用于整个中缀表达式。也就是说,您可以使用括号来明确运算符应用程序的范围。 + +```swift +// try applies to both function calls +sum = try someThrowingFunction() + anotherThrowingFunction() + +// try applies to both function calls +sum = try (someThrowingFunction() + anotherThrowingFunction()) + +// Error: try applies only to the first function call +sum = (try someThrowingFunction()) + anotherThrowingFunction() +``` + + + +`try` 表达式不能出现在中缀运算符的右侧,除非中缀运算符是赋值运算符或者 `try`表达式括在括号中。 + + + + +如果表达式同时包含`try`和`await`运算符,则`try`运算符必须首先出现。 + + + + +有关更多信息并查看如何使用`try`、`try?`的示例,并 `try! ` 请参阅 . + +> try 表达式的语法: +> +> *try-operator* → **`try`** | **`try`** **`?`** | **`try`** **`!`** + +### 等待接线员 + +*wait* 表达式由`await`运算符后跟一个使用异步操作结果的表达式组成。它具有以下形式 + +```swift +await <#expression#> +``` +`await`表达式的值是expression的值。标有await表达式称为 *潜在挂起点* 。异步函数的执行可以在每个用 `await`标记的表达式处暂停。此外,并发代码的执行永远不会在任何其他点暂停。这意味着潜在挂起点之间的代码可以安全地更新需要暂时破坏不变量的状态,前提是它在下一个潜在挂起点之前完成更新。 + + + +`await` 表达式只能出现在异步上下文中,例如传递给 `async(priority:operation:)`函数的尾随闭包。它不能出现在defer语句的主体中,也不能出现在同步函数类型的自动闭包中。 + +当中缀运算符左侧的表达式用`await`运算符标记时,该运算符适用于整个中缀表达式。也就是说,您可以使用括号来明确运算符应用程序的范围。 + +```swift +// await applies to both function calls +sum = await someAsyncFunction() + anotherAsyncFunction() + +// await applies to both function calls +sum = await (someAsyncFunction() + anotherAsyncFunction()) + +// Error: await applies only to the first function call +sum = (await someAsyncFunction()) + anotherAsyncFunction() +``` + + + +`await`表达式不能出现在中缀运算符的右侧,除非中缀运算符是赋值运算符或者将await表达式括在括号中。 + + + +如果表达式同时包含 `await`和try运算符,则try运算符必须首先出现。 + + + +> 等待表达的语法: +> +> *等待运算符* → **`await`** + +## 中缀表达式 + +*中缀表达式* 将中缀二元运算符与其作为其左侧和右侧参数的表达式组合起来。它具有以下形式: + +```swift +<#left-hand argument#> <#operator#> <#right-hand argument#> +``` + +有关这些运算符的行为的信息,请参阅 . + +有关 Swift 标准库提供的运算符的信息,请参阅 [Operator Declarations](https://developer.apple.com/documentation/swift/operator_declarations). + + + +> 注意:在解析时,由中缀运算符组成的表达式表示为平面列表。通过应用运算符优先级将该列表转换为树。例如,表达式2 + 3 * 5最初被理解为五个项目2 、 + 、 3 、 *和5的平面列表。此过程将其转换为树 (2 + (3 * 5))。 + +> 中缀表达式的语法: +> +> *infix-expression* → *infix-operator* *prefix-expression* \ +> *infix-expression* → *assignment-operator* *try-operator*_?_ *await-operator*_?_ *prefix-expression* \ +> *infix-expression* → *conditional-operator* *try-operator*_?_ *await-operator*_?_ *prefix-expression* \ +> *infix-expression* → *type-casting-operator* \ +> *infix-expressions* → *infix-expression* *infix-expressions*_?_ + +### 赋值运算符 + +*赋值运算符* 为给定表达式设置新值。它具有以下形式: + +```swift +<#expression#> = <#value#> +``` + +*表达式* 的值设置为通过计算*value* 获得的值。如果表达式是元组,则值必须是具有相同元素数量的元组。 (允许嵌套元组。)从值的每个部分到表达式的相应部分执行赋值。例如: + +```swift +(a, _, (b, c)) = ("test", 9.45, (12, 3)) +// a is "test", b is 12, c is 3, and 9.45 is ignored +``` + + + +赋值运算符不返回任何值。 + +> 赋值运算符的语法: +> +> *赋值运算符* → **`=`** + +### 三元条件运算符 + +*三元条件运算符*根据条件值计算两个给定值之一。它具有以下形式: + +```swift +<#condition#> ? <#expression used if true#> : <#expression used if false#> +``` + +如果*条件*计算结果为`true` ,则条件运算符计算第一个表达式并返回其值。否则,它计算第二个表达式并返回其值。不计算未使用的表达式。 + +有关使用三元条件运算符的示例,请参阅文档: . + +> 条件运算符的语法: +> +> *条件运算符* → **`?`** *表达* **`:`** + +### 类型转换运算符 + +有四种类型转换运算符: `is`运算符、`as`运算符、`as?`运算符和`as!`操作员。 + +它们具有以下形式: + +```swift +<#expression#> is <#type#> +<#expression#> as <#type#> +<#expression#> as? <#type#> +<#expression#> as! <#type#> +``` + +`is`运算符在运行时检查表达式是否可以转换为指定类型。如果*表达式*可以转换为指定*类型*,则返回`true` ;否则,返回`false` 。 + + + + + +当在编译时已知转换始终成功时,`as`运算符会执行转换,例如向上转换或桥接。向上转换允许您使用表达式作为其类型的超类型的实例,而无需使用中间变量。以下方法是等效的: + +```swift +func f(_ any: Any) { print("Function for Any") } +func f(_ int: Int) { print("Function for Int") } +let x = 10 +f(x) +// Prints "Function for Int" + +let y: Any = x +f(y) +// Prints "Function for Any" + +f(x as Any) +// Prints "Function for Any" +``` + + + +桥接允许您使用`Swift` 标准库类型(例如String的表达式作为其相应的基础类型(例如NSString ,而无需创建新实例。有关桥接的更多信息,请参阅[Working with Foundation Types](https://developer.apple.com/documentation/swift/imported_c_and_objective_c_apis/working_with_foundation_types). + +`as?`运算符执行表达式到指定类型的条件转换。 `as?`运算符返回指定类型的可选值。在运行时,如果转换成功,则将表达式的值包装在可选值中并返回;否则,返回值为`nil` 。如果强制转换为指定类型肯定会失败或一定会成功,则会引发编译时错误。 + +`as!`运算符将表达式强制转换为指定类型。 `as!`运算符返回指定类型的值,而不是可选类型。如果转换失败,则会引发运行时错误。 `x as! T`与 `(x as? T)!` 。 + +有关类型转换的更多信息以及查看使用类型转换运算符的示例,请参阅. + +> 类型转换运算符的语法: +> +> *类型转换运算符* → **`is`** *类型* \ +> *类型转换运算符* → **`as`** *类型* \ +> *类型转换运算符* → **`as`** **`?`** *类型* \ +> *类型转换运算符* → **`as`** **`!`** *类型* + +## 主要表达 + +*初级表达式*是最基本的表达式。它们可以单独用作表达式,也可以与其他标记组合以构成前缀表达式、中缀表达式和后缀表达式。 + +> 基本表达式的语法: +> +> *primary-expression* → *identifier* *generic-argument-clause*_?_ \ +> *primary-expression* → *literal-expression* \ +> *primary-expression* → *self-expression* \ +> *primary-expression* → *superclass-expression* \ +> *primary-expression* → *conditional-expression* \ +> *primary-expression* → *closure-expression* \ +> *primary-expression* → *parenthesized-expression* \ +> *primary-expression* → *tuple-expression* \ +> *primary-expression* → *implicit-member-expression* \ +> *primary-expression* → *wildcard-expression* \ +> *primary-expression* → *macro-expansion-expression* \ +> *primary-expression* → *key-path-expression* \ +> *primary-expression* → *selector-expression* \ +> *primary-expression* → *key-path-string-expression* + + + + + +### 文字表达 + +文字表达式由普通文字(例如字符串或数字)、数组或字典文字或游乐场文字组成 + +> Note: +> Prior to Swift 5.9, +> the following special literals were recognized: +> `#column`, +> `#dsohandle`, +> `#fileID`, +> `#filePath`, +> `#file`, +> `#function`, +> and `#line`. +> These are now implemented as macros in the Swift standard library: +> [`column()`](https://developer.apple.com/documentation/swift/column()), +> [`dsohandle()`](https://developer.apple.com/documentation/swift/dsohandle()), +> [`fileID()`](https://developer.apple.com/documentation/swift/fileID()), +> [`filePath()`](https://developer.apple.com/documentation/swift/filePath()), +> [`file()`](https://developer.apple.com/documentation/swift/file()), +> [`function()`](https://developer.apple.com/documentation/swift/function()), +> and [`line()`](https://developer.apple.com/documentation/swift/line()). + + + +*数组文字*是值的有序集合。它具有以下形式: + +```swift +[<#value 1#>, <#value 2#>, <#...#>] +``` + +数组中的最后一个表达式后面可以跟一个可选的逗号。数组文字的值具有类型`[T]` ,其中T是其中表达式的类型。如果存在多种类型的表达式,则`T` 是它们最接近的公共超类型。空数组文字使用一对空方括号编写,可用于创建指定类型的空数组。 + +```swift +var emptyArray: [Double] = [] +``` + + + +*字典文字* 是键值对的无序集合。它具有以下形式: + +```swift +[<#key 1#>: <#value 1#>, <#key 2#>: <#value 2#>, <#...#>] +``` + +字典中的最后一个表达式后面可以跟一个可选的逗号。字典文字的值具有类型`[Key: Value]` ,其中 `Key`是其键表达式的类型, `Value` 是其值表达式的类型。如果存在多种类型的表达式,则`Key`和`Value`是其各自值最接近的公共超类型。空字典文字被写为一对括号 `( [:] )` 内的冒号,以将其与空数组文字区分开。您可以使用空字典文字来创建指定键和值类型的空字典文字。 + +```swift +var emptyDictionary: [String: Double] = [:] +``` + + + +Xcode 使用 *Playground* 文字在程序编辑器中创建颜色、文件或图像的交互式表示。 Xcode 之外的纯文本 Playground 文字使用特殊的文字语法表示。 + +有关在 Xcode 中使用 Playground 文字的信息,请参阅 Xcode 帮助中[Add a color, file, or image literal](https://help.apple.com/xcode/mac/current/#/dev4c60242fc) + +> 文字表达式的语法: +> +> *literal-expression* → *literal* \ +> *literal-expression* → *array-literal* | *dictionary-literal* | *playground-literal* +> +> *array-literal* → **`[`** *array-literal-items*_?_ **`]`** \ +> *array-literal-items* → *array-literal-item* **`,`**_?_ | *array-literal-item* **`,`** *array-literal-items* \ +> *array-literal-item* → *expression* +> +> *dictionary-literal* → **`[`** *dictionary-literal-items* **`]`** | **`[`** **`:`** **`]`** \ +> *dictionary-literal-items* → *dictionary-literal-item* **`,`**_?_ | *dictionary-literal-item* **`,`** *dictionary-literal-items* \ +> *dictionary-literal-item* → *expression* **`:`** *expression* +> +> *playground-literal* → **`#colorLiteral`** **`(`** **`red`** **`:`** *expression* **`,`** **`green`** **`:`** *expression* **`,`** **`blue`** **`:`** *expression* **`,`** **`alpha`** **`:`** *expression* **`)`** \ +> *playground-literal* → **`#fileLiteral`** **`(`** **`resourceName`** **`:`** *expression* **`)`** \ +> *playground-literal* → **`#imageLiteral`** **`(`** **`resourceName`** **`:`** *expression* **`)`** + +### 自我表达 + +`self`表达式是对当前类型或它所在类型的实例的显式引用。它有以下几种形式: + +```swift +self +self.<#member name#> +self[<#subscript index#>] +self(<#initializer arguments#>) +self.init(<#initializer arguments#>) +``` + + + +在初始值设定项、下标或实例方法中, `self`指的是它出现的类型的当前实例。在类型方法中, `self`指的是它出现的当前类型。 + +`self`表达式用于在访问成员时指定作用域,当作用域中存在另一个同名变量(例如函数参数)时,可以消除歧义。例如: + +```swift +class SomeClass { + var greeting: String + init(greeting: String) { + self.greeting = greeting + } +} +``` + + + +在值类型的变异方法中,您可以将该值类型的新实例分配给 `self` 。例如: + +```swift +struct Point { + var x = 0.0, y = 0.0 + mutating func moveBy(x deltaX: Double, y deltaY: Double) { + self = Point(x: x + deltaX, y: y + deltaY) + } +} +``` + + + + + +> 自我表达的语法: +> +> *self-expression* → **`self`** | *self-method-expression* | *self-subscript-expression* | *self-initializer-expression* +> +> *self-method-expression* → **`self`** **`.`** *identifier* \ +> *self-subscript-expression* → **`self`** **`[`** *function-call-argument-list* **`]`** \ +> *self-initializer-expression* → **`self`** **`.`** **`init`** + +### 超类表达式 + +*超类表达式*允许类与其超类交互。它具有以下形式之一: + +```swift +super.<#member name#> +super[<#subscript index#>] +super.init(<#initializer arguments#>) +``` + +第一种形式用于访问超类的成员。第二种形式用于访问超类的下标实现。第三种形式用于访问超类的初始值设定项。 + +子类可以在其成员、下标和初始化器的实现中使用超类表达式,以利用其超类中的实现。 + +> 超类表达式的语法: +> +> *superclass-expression* → *superclass-method-expression* | *superclass-subscript-expression* | *superclass-initializer-expression* +> +> *superclass-method-expression* → **`super`** **`.`** *identifier* \ +> *superclass-subscript-expression* → **`super`** **`[`** *function-call-argument-list* **`]`** \ +> *superclass-initializer-expression* → **`super`** **`.`** **`init`** + +### 条件表达式 + +*条件表达式*根据条件值计算为多个给定值之一。它具有以下形式之一: + +```swift +if <#condition 1#> { + <#expression used if condition 1 is true#> +} else if <#condition 2#> { + <#expression used if condition 2 is true#> +} else { + <#expression used if both conditions are false#> +} + +switch <#expression#> { +case <#pattern 1#>: + <#expression 1#> +case <#pattern 2#> where <#condition#>: + <#expression 2#> +default: + <#expression 3#> +} +``` + +除了以下段落描述的差异之外,条件表达式与`if`语句或`switch`语句具有相同的行为和语法。 + +条件表达式仅出现在以下上下文中: + +- 作为分配给变量的值。 +- 作为变量或常量声明中的初始值。 +- 作为由 `throw `表达式引发的错​​误。 +- 作为函数、闭包或属性 `getter` 返回的值。 +- 作为条件表达式分支内的值。 + +条件表达式的分支是详尽的,确保无论条件如何,表达式始终生成一个值。这意味着每个if分支都需要一个相应的else分支。 + +每个分支包含一个表达式(当该分支的条件为 true 时用作条件表达式的值)、一个 `throw`语句或对永不返回的函数的调用。 + +每个分支必须产生相同类型的值。由于每个分支的类型检查是独立的,因此有时需要显式指定值的类型,例如当分支包含不同类型的文字时,或者当分支的值为`nil`时。当您需要提供此信息时,请向结果分配到的变量添加类型注释,或向分支的值添加`as`强制转换。 + +```swift +let number: Double = if someCondition { 10 } else { 12.34 } +let number = if someCondition { 10 as Double } else { 12.34 } +``` + +在结果生成器中,条件表达式只能显示为变量或常量的初始值。此行为意味着当您在结果生成器中编写`if`或`switch` 时(在变量或常量声明之外),该代码将被理解为分支语句,并且结果生成器的方法之一会转换该代码。 + +不要将条件表达式放入try表达式中,即使条件表达式的分支之一抛出异常。 + +> 条件句语法: +> +> *conditional-expression* → *if-expression* | *switch-expression* +> +> *if-expression* → **`if`** *condition-list* **`{`** *statement* **`}`** *if-expression-tail* \ +> *if-expression-tail* → **`else`** *if-expression* \ +> *if-expression-tail* → **`else`** **`{`** *statement* **`}`** +> +> *switch-expression* → **`switch`** *expression* **`{`** *switch-expression-cases* **`}`** \ +> *switch-expression-cases* → *switch-expression-case* *switch-expression-cases*_?_ \ +> *switch-expression-case* → *case-label* *statement* \ +> *switch-expression-case* → *default-label* *statement* + +### 闭包表达式 + +闭包表达式创建一个闭包,在其他编程语言中也称为*lambda*或匿名函数。与函数声明一样,闭包包含语句,并且它从其封闭范围捕获常量和变量。它具有以下形式: + +```swift +{ (<#parameters#>) -> <#return type#> in + <#statements#> +} +``` + +这些参数与函数声明中的参数具有相同的形式,如。 + +在闭包表达式中写入`throws`或`async`显式地将闭包标记为抛出或异步。 + +```swift +{ (<#parameters#>) async throws -> <#return type#> in + <#statements#> +} +``` + +如果闭包的主体包含一个`throws`语句或一个未嵌套在具有详尽错误处理的`do`语句内的`try`表达式,则该闭包被理解为抛出。如果抛出闭包仅抛出单一类型的错误,则该闭包被理解为抛出该错误类型;否则,它被理解为抛出 `any Error` 。同样,如果主体包含`await`表达式,则它被理解为异步的。 + +有几种特殊的形式可以让闭包写得更简洁: + + + +- 闭包可以省略其参数类型、返回类型或两者。如果省略参数名称和两种类型,请省略语句前的`in`关键字。如果无法推断省略的类型,则会引发编译时错误。 + +- 闭包可以省略其参数的名称。然后,其参数隐式命名为`$`后跟其位置: `$0` 、 `$1 ` 、 `$2`等。 + +- 仅包含单个表达式的闭包被理解为返回该表达式的值。对周围表达式执行类型推断时,也会考虑该表达式的内容。 + +以下闭包表达式是等效的: + +```swift +myFunction { (x: Int, y: Int) -> Int in + return x + y +} + +myFunction { x, y in + return x + y +} + +myFunction { return $0 + $1 } + +myFunction { $0 + $1 } +``` + + + +有关将闭包作为参数传递给函数的信息,请参阅 . + +闭包表达式可以在不存储在变量或常量中的情况下使用,例如当您立即使用闭包作为函数调用的一部分时。上面代码中传递给`myFunction`闭包表达式就是这种立即使用的示例。因此,闭包表达式是转义还是非转义取决于表达式的周围上下文。如果立即调用闭包表达式或作为非转义函数参数传递,则闭包表达式是非转义的。否则,闭包表达式就会转义。 + +有关转义闭包的更多信息,请参阅文档:. + +#### 捕获列表 + +默认情况下,闭包表达式从其周围范围捕获常量和变量,并对这些值进行强引用。您可以使用捕获列表来显式控制如何在闭包中捕获值。 + +捕获列表写为以逗号分隔的表达式列表,并用方括号括起来,位于参数列表之前。如果使用捕获列表,则即使省略参数名称、参数类型和返回类型,也必须使用`in`关键字。 + +捕获列表中的条目在创建闭包时被初始化。对于捕获列表中的每个条目,常量被初始化为周围范围中具有相同名称的常量或变量的值。例如,在下面的代码中, `a`包含在捕获列表中,但`b`不包含在捕获列表中,这使它们具有不同的行为。 + +```swift +var a = 0 +var b = 0 +let closure = { [a] in + print(a, b) +} + +a = 10 +b = 10 +closure() +// Prints "0 10" +``` + + + +有两种不同的东西,名为`a` ,周围作用域中的变量和闭包作用域中的常量,但只有一个名为`b` 变量。创建闭包时,内部作用域中的`a`会使用外部作用域中a的值进行初始化,但它们的值不会以任何特殊方式连接。这意味着外部作用域中a值的更改不会影响内部作用域中`a`的值,闭包内部a的更改也不会影响闭包外部a的值。相比之下,只有一个名为b的变量——外部作用域中的`b`因此来自闭包内部或外部的更改在两个地方都可见。 + + + +当捕获的变量的类型具有引用语义时,这种区别不可见。例如,下面的代码中有两个名为`x`的东西,外部作用域中的变量和内部作用域中的常量,但由于引用语义,它们都引用同一个对象。 + +```swift +class SimpleClass { + var value: Int = 0 +} +var x = SimpleClass() +var y = SimpleClass() +let closure = { [x] in + print(x.value, y.value) +} + +x.value = 10 +y.value = 10 +closure() +// Prints "10 10" +``` + + + + + + + + + +如果表达式值的类型是类,则可以使用`weak`或`unowned`标记捕获列表中的表达式,以捕获对该表达式值的弱或无主引用。 + +```swift +myFunction { print(self.title) } // implicit strong capture +myFunction { [self] in print(self.title) } // explicit strong capture +myFunction { [weak self] in print(self!.title) } // weak capture +myFunction { [unowned self] in print(self.title) } // unowned capture +``` + + + +您还可以将任意表达式绑定到捕获列表中的命名值。创建闭包时将对表达式求值,并以指定的强度捕获该值。例如: + +```swift +// Weak capture of "self.parent" as "parent" +myFunction { [weak parent = self.parent] in print(parent!.title) } +``` + + + +有关闭包表达式的更多信息和示例,请参阅文档: . +关捕获列表的更多信息和示例,请参阅文档:. + + + +> 闭包表达式的语法: +> +> *closure-expression* → **`{`** *attributes*_?_ *closure-signature*_?_ *statements*_?_ **`}`** +> +> *closure-signature* → *capture-list*_?_ *closure-parameter-clause* **`async`**_?_ *throws-clause*_?_ *function-result*_?_ **`in`** \ +> *closure-signature* → *capture-list* **`in`** +> +> *closure-parameter-clause* → **`(`** **`)`** | **`(`** *closure-parameter-list* **`)`** | *identifier-list* \ +> *closure-parameter-list* → *closure-parameter* | *closure-parameter* **`,`** *closure-parameter-list* \ +> *closure-parameter* → *closure-parameter-name* *type-annotation*_?_ \ +> *closure-parameter* → *closure-parameter-name* *type-annotation* **`...`** \ +> *closure-parameter-name* → *identifier* +> +> *capture-list* → **`[`** *capture-list-items* **`]`** \ +> *capture-list-items* → *capture-list-item* | *capture-list-item* **`,`** *capture-list-items* \ +> *capture-list-item* → *capture-specifier*_?_ *identifier* \ +> *capture-list-item* → *capture-specifier*_?_ *identifier* **`=`** *expression* \ +> *capture-list-item* → *capture-specifier*_?_ *self-expression* \ +> *capture-specifier* → **`weak`** | **`unowned`** | **`unowned(safe)`** | **`unowned(unsafe)`** + +### 隐式成员表达式 + +*隐式成员*表达式是在类型推断可以确定隐含类型的上下文中访问类型成员(例如枚举情况或类型方法)的缩写方式。它具有以下形式: + +```swift +.<#member name#> +``` + +例如: + +```swift +var x = MyEnumeration.someValue +x = .anotherValue +``` + + + +如果推断类型是可选类型,则还可以在隐式成员表达式中使用非可选类型的成员。 + +```swift +var someOptional: MyEnumeration? = .someValue +``` + + + +隐式成员表达式后面可以跟后缀运算符或中列出的其他后缀语法。这称为*链式隐式成员表达式*。尽管所有链接的后缀表达式都具有相同的类型是很常见的,但唯一的要求是整个链接的隐式成员表达式需要可转换为其上下文隐含的类型。具体来说,如果隐含类型是可选类型,则可以使用非可选类型的值,如果隐含类型是类类型,则可以使用其子类之一的值。例如: + +```swift +class SomeClass { + static var shared = SomeClass() + static var sharedSubclass = SomeSubclass() + var a = AnotherClass() +} +class SomeSubclass: SomeClass { } +class AnotherClass { + static var s = SomeClass() + func f() -> SomeClass { return AnotherClass.s } +} +let x: SomeClass = .shared.a.f() +let y: SomeClass? = .shared +let z: SomeClass = .sharedSubclass +``` + + + +在上面的代码中, `x` 的类型与其上下文隐含的类型完全匹配, `y` 的类型可以从 `SomeClass` 转换为 `SomeClass?` ,并且 `z` 的类型可以从 `SomeSubclass` 转换为 `SomeClass` 。 + +> 隐式成员表达式的语法: +> +> *implicit-member-expression* → **`.`** *identifier* \ +> *implicit-member-expression* → **`.`** *identifier* **`.`** *postfix-expression* + + + + + +### 带括号的表达式 + +带括号的表达式由括号包围的表达式组成。您可以使用括号通过显式分组表达式来指定运算的优先级。分组括号不会更改表达式的类型 --- 例如, `(1)` 的类型只是 `Int` + + + +> 括号表达式的语法 +> +> *parenthesized-expression* → **`(`** *expression* **`)`** + +### 元组表达式 + +*元组表达式*由逗号分隔的表达式列表组成,并用括号括起来。每个表达式前面可以有一个可选标识符,用冒号 (`:`) 分隔。它具有以下形式: + +```swift +(<#identifier 1#>: <#expression 1#>, <#identifier 2#>: <#expression 2#>, <#...#>) +``` + +元组表达式中的每个标识符在元组表达式的范围内必须是唯一的。在嵌套元组表达式中,同一嵌套级别的标识符必须是唯一的。例如, `(a: 10, a: 20)` 是无效的,因为标签 `a` 在同一级别出现了两次。然而, `(a: 10, b: (a: 1, x: 2))` 是有效的——虽然 `a`出现了两次,但它在外元组中出现一次,在内元组中出现一次。 + + + +元组表达式可以包含零个表达式,也可以包含两个或多个表达式。括号内的单个表达式是括号表达式。 + +> 注意:Swift 中空元组表达式和空元组类型都写成 `()` 。因为 `Void` 是 `()` 的类型别名,所以您可以使用它来编写空元组类型。然而,像所有类型别名一样, `Void` 始终是一种类型——您不能使用它来编写空元组表达式。 + +> 元组表达式的语法: +> +> *tuple-expression* → **`(`** **`)`** | **`(`** *tuple-element* **`,`** *tuple-element-list* **`)`** \ +> *tuple-element-list* → *tuple-element* | *tuple-element* **`,`** *tuple-element-list* \ +> *tuple-element* → *expression* | *identifier* **`:`** *expression* + +### 通配符表达式 + +*通配符表达式* 用于在赋值期间显式忽略某个值。例如,在以下赋值中,`10` 被分配给x ,20 被忽略: + + + +```swift +(x, _) = (10, 20) +// x is 10, and 20 is ignored +``` + + + +> 通配符表达式的语法: +> +> *wildcard-expression* → **`_`** + +### 宏展开表达式 + +*宏扩展表达式* 由宏名称和后跟括号中的以逗号分隔的宏参数列表组成。宏在编译时展开。宏展开表达式具有以下形式: + +```swift +<#macro name#>(<#macro argument 1#>, <#macro argument 2#>) +``` + +宏扩展表达式不能作为参数的默认值出现,除了 Swift 标准库中的 `file()` 和 `line()` 宏。当用作函数或方法参数的默认值时,这些宏将使用调用站点的源代码位置(而不是它们在函数定义中出现的位置)进行计算。 + +[`file()`]: https://developer.apple.com/documentation/swift/file() +[`line()`]: https://developer.apple.com/documentation/swift/line() + +您可以使用宏表达式来调用独立宏。要调用附加的宏,请使用 中描述的自定义属性语法。独立宏和附加宏都扩展如下: + + +1. Swift 解析源代码以生成抽象语法树(AST)。 + +2. 宏实现接收 AST 节点作为其输入并执行该宏所需的转换。 + +3. 宏实现生成的转换后的 AST 节点将添加到原始 AST 中。 + +每个宏的扩展都是独立且自成体系的。但是,作为性能优化,Swift 可能会启动一个实现宏的外部进程,并重用同一进程来扩展多个宏。当您实现宏时,该代码不得依赖于您的代码之前扩展的宏,或任何其他外部状态(例如当前时间)。 + +对于具有多个角色的嵌套宏和附加宏,会重复展开过程。嵌套宏展开表达式从外向内展开。例如,在下面的代码中, `outerMacro(_:) `首先展开,未展开的对`innerMacro(_:)`调用出现在 `outerMacro(_:)`接收的抽象语法树中。输入 + +```swift +#outerMacro(12, #innerMacro(34), "some text") +``` + +具有多个角色的附加宏将为每个角色扩展一次。每个扩展都接收相同的原始 AST 作为其输入。 Swift 通过收集所有生成的 AST 节点并将它们放在 AST 中相应的位置来形成整体扩展。 + +有关 Swift 中宏的概述,请参阅 . + +> 宏展开表达式的语法: +> +> *macro-expansion-expression* → **`#`** *identifier* *generic-argument-clause*_?_ *function-call-argument-clause*_?_ *trailing-closures*_?_ + +### 键路径表达式 + +*键路径表达式*指的是类型的属性或下标。您可以在动态编程任务中使用键路径表达式,例如键值观察。它们具有以下形式: + +```swift +\<#type name#>.<#path#> +``` + +*类型名称*是具体类型的名称,包括任何泛型参数,例如 `String` 、 `[Int]` 或 `Set` 。 + +该*路径*由属性名称、下标、可选链表达式和强制展开表达式组成。这些关键路径组件中的每一个都可以根据需要以任何顺序重复多次。 + +在编译时,键路径表达式被[`KeyPath`](https://developer.apple.com/documentation/swift/keypath) 类的实例替换。 + +要使用键路径访问值,请将键路径传递给 `subscript(keyPath:)` 下标,该下标适用于所有类型。例如: + + + +```swift +struct SomeStructure { + var someValue: Int +} + +let s = SomeStructure(someValue: 12) +let pathToProperty = \SomeStructure.someValue + +let value = s[keyPath: pathToProperty] +// value is 12 +``` + + + +在类型推断可以确定隐含类型的上下文中,可以省略类型名称。以下代码使用 `\.someProperty` 而不是 `\SomeClass.someProperty` : + +```swift +class SomeClass: NSObject { + @objc dynamic var someProperty: Int + init(someProperty: Int) { + self.someProperty = someProperty + } +} + +let c = SomeClass(someProperty: 10) +c.observe(\.someProperty) { object, change in + // ... +} +``` + + + + + +该*路径* 可以引用self来创建身份密钥路径 `( \.self )`。身份键路径引用整个实例,因此您可以使用它一步来访问和更改存储在变量中的所有数据。例如: + +```swift +var compoundValue = (a: 1, b: 2) +// Equivalent to compoundValue = (a: 10, b: 20) +compoundValue[keyPath: \.self] = (a: 10, b: 20) +``` + + + +该路径可以包含多个属性名称,以句点分隔,以引用属性值的属性。此代码使用关键路径表达式 `\OuterStructure.outer.someValue` 访问 `OuterStructure` 类型的 `outer` 属性的 `someValue` 属性: + +```swift +struct OuterStructure { + var outer: SomeStructure + init(someValue: Int) { + self.outer = SomeStructure(someValue: someValue) + } +} + +let nested = OuterStructure(someValue: 24) +let nestedKeyPath = \OuterStructure.outer.someValue + +let nestedValue = nested[keyPath: nestedKeyPath] +// nestedValue is 24 +``` + + + +*路径*可以包含使用括号的下标,只要下标的参数类型符合 `Hashable` 协议即可。此示例使用键路径中的下标来访问数组的第二个元素: + +```swift +let greetings = ["hello", "hola", "bonjour", "안녕"] +let myGreeting = greetings[keyPath: \[String].[1]] +// myGreeting is 'hola' +``` + + + + + +下标中使用的值可以是命名值或文字。使用值语义在关键路径中捕获值。以下代码在键路径表达式和闭包中使用变量 `index` 来访问 `greetings` 数组的第三个元素。当 `index` 被修改时,键路径表达式仍然引用第三个元素,而闭包使用新索引。 + +```swift +var index = 2 +let path = \[String].[index] +let fn: ([String]) -> String = { strings in strings[index] } + +print(greetings[keyPath: path]) +// Prints "bonjour" +print(fn(greetings)) +// Prints "bonjour" + +// Setting 'index' to a new value doesn't affect 'path' +index += 1 +print(greetings[keyPath: path]) +// Prints "bonjour" + +// Because 'fn' closes over 'index', it uses the new value +print(fn(greetings)) +// Prints "안녕" +``` + + + +该路径可以使用可选链接和强制展开。此代码在键路径中使用可选链接来访问可选字符串的属性: + +```swift +let firstGreeting: String? = greetings.first +print(firstGreeting?.count as Any) +// Prints "Optional(5)" + +// Do the same thing using a key path. +let count = greetings[keyPath: \[String].first?.count] +print(count as Any) +// Prints "Optional(5)" +``` + + + + + +您可以混合和匹配关键路径的组件来访问深度嵌套在类型中的值。以下代码通过使用组合这些组件的键路径表达式来访问数组字典的不同值和属性。 + +```swift +let interestingNumbers = ["prime": [2, 3, 5, 7, 11, 13, 17], + "triangular": [1, 3, 6, 10, 15, 21, 28], + "hexagonal": [1, 6, 15, 28, 45, 66, 91]] +print(interestingNumbers[keyPath: \[String: [Int]].["prime"]] as Any) +// Prints "Optional([2, 3, 5, 7, 11, 13, 17])" +print(interestingNumbers[keyPath: \[String: [Int]].["prime"]![0]]) +// Prints "2" +print(interestingNumbers[keyPath: \[String: [Int]].["hexagonal"]!.count]) +// Prints "7" +print(interestingNumbers[keyPath: \[String: [Int]].["hexagonal"]!.count.bitWidth]) +// Prints "64" +``` + + + +您可以在通常提供函数或闭包的上下文中使用键路径表达式。具体来说,您可以使用根类型为 `SomeType` 且其路径生成 `Value` 类型的值的键路径表达式,而不是 `(SomeType) -> Value` 类型的函数或闭包。 + +```swift +struct Task { + var description: String + var completed: Bool +} +var toDoList = [ + Task(description: "Practice ping-pong.", completed: false), + Task(description: "Buy a pirate costume.", completed: true), + Task(description: "Visit Boston in the Fall.", completed: false), +] + +// Both approaches below are equivalent. +let descriptions = toDoList.filter(\.completed).map(\.description) +let descriptions2 = toDoList.filter { $0.completed }.map { $0.description } +``` + + + + + +关键路径表达式的任何副作用仅在计算表达式的点进行计算。例如,如果您在关键路径表达式的下标内进行函数调用,则该函数仅在计算表达式时调用一次,而不是每次使用关键路径时都被调用。 + +```swift +func makeIndex() -> Int { + print("Made an index") + return 0 +} +// The line below calls makeIndex(). +let taskKeyPath = \[Task][makeIndex()] +// Prints "Made an index" + +// Using taskKeyPath doesn't call makeIndex() again. +let someTask = toDoList[keyPath: taskKeyPath] +``` + + + +有关在与 Objective-C API 交互的代码中使用关键路径的更多信息,请参阅 [Using Objective-C Runtime Features in Swift](https://developer.apple.com/documentation/swift/using_objective_c_runtime_features_in_swift). +有关键值编码和键值观察的信息,请参阅[Key-Value Coding Programming Guide](https://developer.apple.com/library/content/documentation/Cocoa/Conceptual/KeyValueCoding/index.html#//apple_ref/doc/uid/10000107i) +和 [Key-Value Observing Programming Guide](https://developer.apple.com/library/content/documentation/Cocoa/Conceptual/KeyValueObserving/KeyValueObserving.html#//apple_ref/doc/uid/10000177i). + +> 键路径表达式的语法: +> +> *key-path-expression* → **`\`** *type*_?_ **`.`** *key-path-components* \ +> *key-path-components* → *key-path-component* | *key-path-component* **`.`** *key-path-components* \ +> *key-path-component* → *identifier* *key-path-postfixes*_?_ | *key-path-postfixes* +> +> *key-path-postfixes* → *key-path-postfix* *key-path-postfixes*_?_ \ +> *key-path-postfix* → **`?`** | **`!`** | **`self`** | **`[`** *function-call-argument-list* **`]`** + +### 选择器表达式 + +选择器表达式允许您访问用于引用 Objective-C 中的方法或属性的 getter 或 setter 的选择器。它具有以下形式: + +```swift +#selector(<#method name#>) +#selector(getter: <#property name#>) +#selector(setter: <#property name#>) +``` + +方法名称和属性名称必须是对 Objective-C 运行时中可用的方法或属性的引用。选择器表达式的值是 `Selector` 类型的实例。例如: + +```swift +class SomeClass: NSObject { + @objc let property: String + + @objc(doSomethingWithInt:) + func doSomething(_ x: Int) { } + + init(property: String) { + self.property = property + } +} +let selectorForMethod = #selector(SomeClass.doSomething(_:)) +let selectorForPropertyGetter = #selector(getter: SomeClass.property) +``` + + + +为属性的 getter 创建选择器时,*属性名称*可以是对变量或常量属性的引用。相反,当为属性的设置器创建选择器时,*属性名称* 必须仅是对变量属性的引用。 + +*方法名称*可以包含用于分组的括号,以及用于消除共享名称但具有不同类型签名的方法之间的歧义的 `as`运算符。例如: + +```swift +extension SomeClass { + @objc(doSomethingWithString:) + func doSomething(_ x: String) { } +} +let anotherSelector = #selector(SomeClass.doSomething(_:) as (SomeClass) -> (String) -> Void) +``` + + -> 模式语法: +因为选择器是在编译时创建的,而不是在运行时创建的,所以编译器可以检查方法或属性是否存在以及它们是否暴露给 Objective-C 运行时。 + +> 注意:虽然*方法名称*和*属性名称*是表达式,但它们永远不会被求值 + +有关在与 Objective-C API 交互的 Swift 代码中使用选择器的更多信息,请参阅[Using Objective-C Runtime Features in Swift](https://developer.apple.com/documentation/swift/using_objective_c_runtime_features_in_swift). + +> 选择器表达式的语法: > -> *pattern* → *wildcard-pattern* *type-annotation*_?_ \ -> *pattern* → *identifier-pattern* *type-annotation*_?_ \ -> *pattern* → *value-binding-pattern* \ -> *pattern* → *tuple-pattern* *type-annotation*_?_ \ -> *pattern* → *enum-case-pattern* \ -> *pattern* → *optional-pattern* \ -> *pattern* → *type-casting-pattern* \ -> *pattern* → *expression-pattern* +> *selector-expression* → **`#selector`** **`(`** *expression* **`)`** \ +> *selector-expression* → **`#selector`** **`(`** **`getter:`** *expression* **`)`** \ +> *selector-expression* → **`#selector`** **`(`** **`setter:`** *expression* **`)`** + + + +### 键路径字符串表达式 + +键路径字符串表达式允许您访问用于引用 Objective-C 中的属性的字符串,以用于键值编码和键值观察 API。它具有以下形式: + +```swift +#keyPath(<#property name#>) +``` + +*属性名称*必须是对 Objective-C 运行时中可用的属性的引用。在编译时,键路径字符串表达式被替换为字符串文字。例如: -## 通配符模式 +```swift +class SomeClass: NSObject { + @objc var someProperty: Int + init(someProperty: Int) { + self.someProperty = someProperty + } +} + +let c = SomeClass(someProperty: 12) +let keyPath = #keyPath(SomeClass.someProperty) + +if let value = c.value(forKey: keyPath) { + print(value) +} +// Prints "12" +``` + + + +当您在类中使用键路径字符串表达式时,您可以通过仅编写属性名称而不编写类名称来引用该类的属性。 ```swift -for _ in 1...3 { - // Do something three times. +extension SomeClass { + func getSomeKeyPath() -> String { + return #keyPath(someProperty) + } } +print(keyPath == c.getSomeKeyPath()) +// Prints "true" ``` -> 通配符模式的语法: +由于关键路径字符串是在编译时而不是运行时创建的,因此编译器可以检查该属性是否存在以及该属性是否公开给 Objective-C 运行时。 + +有关在与 Objective-C API 交互的 Swift 代码中使用关键路径的更多信息,请参阅[Using Objective-C Runtime Features in Swift](https://developer.apple.com/documentation/swift/using_objective_c_runtime_features_in_swift)。 +有关键值编码和键值观察的信息,请参阅 [Key-Value Coding Programming Guide](https://developer.apple.com/library/content/documentation/Cocoa/Conceptual/KeyValueCoding/index.html#//apple_ref/doc/uid/10000107i) +和 [Key-Value Observing Programming Guide](https://developer.apple.com/library/content/documentation/Cocoa/Conceptual/KeyValueObserving/KeyValueObserving.html#//apple_ref/doc/uid/10000177i)。 + +> 注意:虽然*属性名称*是一个表达式,但它永远不会被计算。 + +> 键路径字符串表达式的语法: +> +> *键路径字符串表达式* → **`#keyPath`** **`(`** *表达式* **`)`** + +## 后缀表达式 + +*后缀表达式*是通过对表达式应用后缀运算符或其他后缀语法来形成的。从语法上来说,每个主表达式也是一个后缀表达式。 + +有关这些运算符的行为的信息,请参阅。 + +有关 Swift 标准库提供的运算符的信息,请参阅[Operator Declarations](https://developer.apple.com/documentation/swift/operator_declarations)。 + +> 后缀表达式的语法: > -> *wildcard-pattern* → **`_`** +> *postfix-expression* → *primary-expression* \ +> *postfix-expression* → *postfix-expression* *postfix-operator* \ +> *postfix-expression* → *function-call-expression* \ +> *postfix-expression* → *initializer-expression* \ +> *postfix-expression* → *explicit-member-expression* \ +> *postfix-expression* → *postfix-self-expression* \ +> *postfix-expression* → *subscript-expression* \ +> *postfix-expression* → *forced-value-expression* \ +> *postfix-expression* → *optional-chaining-expression* + +### 函数调用表达式 + + + +函数调用*表达式*由函数名称和后跟括号中的以逗号分隔的函数参数列表组成。函数调用表达式具有以下形式: + +```swift +<#function name#>(<#argument value 1#>, <#argument value 2#>) +``` + +*函数名称*可函数名可以是任何其值是函数类型的表达式。 -## 标识符模式 +如果函数定义包含其参数名称,则函数调用必须在其参数值之前包含名称,并用冒号(`:`)分隔。 +这种函数调用表达式具有以下形式: -*标识符模式* 匹配任何值并将匹配的值绑定到变量或常量名称.例如,在以下常量声明中`someValue` 是与 `Int` 类型的值 `42` 匹配的标识符模式: +```swift +<#function name#>(<#argument name 1#>: <#argument value 1#>, <#argument name 2#>: <#argument value 2#>) +``` + +函数调用表达式可以在紧跟在右括号之后以闭包表达式的形式包含尾随闭包。尾随闭包被理解为函数的参数,添加在最后一个带括号的参数之后。第一个闭包表达式是无标签的;任何其他闭包表达式前面都有其参数标签。下面的示例显示了使用和不使用尾随闭包语法的函数调用的等效版本: ```swift -let someValue = 42 +// someFunction takes an integer and a closure as its arguments +someFunction(x: x, f: { $0 == 13 }) +someFunction(x: x) { $0 == 13 } + +// anotherFunction takes an integer and two closures as its arguments +anotherFunction(x: x, f: { $0 == 13 }, g: { print(99) }) +anotherFunction(x: x) { $0 == 13 } g: { print(99) } ``` -当匹配成功时,值 `42` 被绑定(分配)到常量名称 `someValue` . + -当变量或常量声明左侧的模式是标识符模式时,标识符模式隐式是值绑定模式的子模式. +如果尾随闭包是函数的唯一参数,则可以省略括号。 -> 标识符模式的语法: -> -> *identifier-pattern* → *identifier* +```swift +// someMethod takes a closure as its only argument +myData.someMethod() { $0 == 13 } +myData.someMethod { $0 == 13 } +``` + + -## 价值绑定模式 + + +为了在参数中包含尾随闭包,编译器从左到右检查函数的参数,如下所示: + +| 尾随闭包 | 范围 | 行动 | +| ---------------- | --------- | ------ | +| 贴上标签 | 贴上标签 | 如果标签相同,则闭包与参数匹配;否则,该参数将被跳过。| +| 贴上标签 | 未标记 | 该参数被跳过。 | +| 未标记 | 有标签或无标签 | 如果参数在结构上类似于函数类型(如下定义),则闭包与参数匹配;否则,该参数将被跳过。 | + +尾随闭包作为其匹配参数的参数传递。在扫描过程中跳过的参数没有传递给它们的参数——例如,它们可以使用默认参数。找到匹配项后,将继续扫描下一个尾随闭包和下一个参数。在匹配过程结束时,所有尾随闭包都必须有匹配项。 + +如果参数不是输入输出参数,并且参数是以下之一,则该参数在结构上类似于函数类型: + +- 类型为函数类型的参数,如`(Bool) -> Int` +- 一个自动闭包参数,其包装表达式的类型是函数类型,例如 `@autoclosure () -> ((Bool) -> Int)` +- 数组元素类型为函数类型的可变参数,例如`((Bool) -> Int)...` +- 其类型被包裹在一层或多层可选中的参数,例如`Optional<(Bool) -> Int>` +- 其类型组合了这些允许类型的参数,例如 `(Optional<(Bool) -> Int>)...` + +当尾随闭包与结构上类似于函数类型但不是函数的参数匹配时,闭包将根据需要进行包装。例如,如果参数的类型是可选类型,则闭包会自动包装在 `Optional` 中. -*值绑定模式* 将匹配的值绑定到变量或常量名称。将匹配值绑定到常量名称的值绑定模式以 `let` 关键字开头;那些绑定到变量名称的变量以`var`关键字开头. + -值绑定模式中的标识符模式将新的命名变量或常量绑定到其匹配值。例如,您可以分解元组的元素并将每个元素的值绑定到相应的标识符模式 +为了简化从 5.3 之前的 Swift 版本(执行从右到左的匹配)的代码迁移,编译器会检查从左到右和从右到左的顺序。如果扫描方向产生不同的结果,则使用旧的从右到左排序,并且编译器会生成警告。 Swift 的未来版本将始终使用从左到右的排序。 ```swift -let point = (3, 2) -switch point { -// Bind x and y to the elements of point. -case let (x, y): - print("The point is at (\(x), \(y)).") +typealias Callback = (Int) -> Int +func someFunction(firstClosure: Callback? = nil, + secondClosure: Callback? = nil) { + let first = firstClosure?(10) + let second = secondClosure?(20) + print(first ?? "-", second ?? "-") } -// Prints "The point is at (3, 2)." + +someFunction() // Prints "- -" +someFunction { return $0 + 100 } // Ambiguous +someFunction { return $0 } secondClosure: { return $0 } // Prints "10 20" ``` -在上面的示例中, `let` 分配给元组模式`(x, y)` 中的每个标识符模式。由于此行为, `switch` case `case let (x, y):` 和`case (let x, let y):` 匹配相同的值 +在上面的示例中,标记为“Ambigitude”的函数调用会打印“- 120”,并在 Swift 5.3 上生成编译器警告。 Swift 的未来版本将打印“110 -”。 -> 值绑定模式的语法: -> -> *value-binding-pattern* → **`var`** *pattern* | **`let`** *pattern* + + +类、结构或枚举类型可以通过声明多种方法之一来启用函数调用语法的语法糖,如 中所述。 + +#### 隐式转换为指针类型 + +在函数调用表达式中,如果参数和参数具有不同的类型,编译器会尝试通过应用以下列表中的隐式转换之一来使它们的类型匹配: + +- `inout SomeType` 可以成为 +`UnsafePointer` 或 `UnsafeMutablePointer` +- `inout Array` 可以成为 +`UnsafePointer`或`UnsafeMutablePointer` +- `Array`可以成为`UnsafePointer` +- `String`可以成为`UnsafePointer` + +以下两个函数调用是等效的: + +```swift +func unsafeFunction(pointer: UnsafePointer) { + // ... +} +var myNumber = 1234 + +unsafeFunction(pointer: &myNumber) +withUnsafePointer(to: myNumber) { unsafeFunction(pointer: $0) } +``` + + + +通过这些隐式转换创建的指针仅在函数调用期间有效。为了避免未定义的行为,请确保您的代码在函数调用结束后永远不会保留指针。 + +> 当将数组隐式转换为不安全指针时,Swift 通过根据需要转换或复制数组来确保数组的存储是连续的。例如,您可以将此语法与从 `NSArray` 子类桥接到 `Array` 的数组一起使用,该子类不对其存储制定任何 API 约定。如果您需要保证数组的存储已经是连续的,因此隐式转换永远不需要执行此工作,请使用 `ContiguousArray` 而不是 `Array` 。 + +使用`&`而不是像`withUnsafePointer(to:)`这样的显式函数可以帮助提高对低级 C 函数的调用的可读性,特别是当函数采用多个指针参数时。但是,当从其他 Swift 代码调用函数时,请避免使用`&`而应显式使用不安全的 API。 -## 元组模式 +> 函数调用表达式的语法: +> +> *function-call-expression* → *postfix-expression* *function-call-argument-clause* \ +> *function-call-expression* → *postfix-expression* *function-call-argument-clause*_?_ *trailing-closures* +> +> *function-call-argument-clause* → **`(`** **`)`** | **`(`** *function-call-argument-list* **`)`** \ +> *function-call-argument-list* → *function-call-argument* | *function-call-argument* **`,`** *function-call-argument-list* \ +> *function-call-argument* → *expression* | *identifier* **`:`** *expression* \ +> *function-call-argument* → *operator* | *identifier* **`:`** *operator* +> +> *trailing-closures* → *closure-expression* *labeled-trailing-closures*_?_ \ +> *labeled-trailing-closures* → *labeled-trailing-closure* *labeled-trailing-closures*_?_ \ +> *labeled-trailing-closure* → *identifier* **`:`** *closure-expression* + +### 初始化表达式 -*元组模式* 是零个或多个模式的逗号分隔列表,括在括号中。元组模式匹配相应元组类型的值 +初始值设定项表达式提供对类型的初始值设定项的访问。它具有以下形式: -您可以使用类型注释来约束元组模式以匹配某些类型的元组类型。例如,常量声明中的元组模式`(x, y): (Int, Int)` `let (x, y): (Int, Int) = (1, 2)` 仅匹配两个元素均为 `Int` 类型的元组类型`. +```swift +<#expression#>.init(<#initializer arguments#>) +``` -当元组模式用作 `for` - `in` 语句或变量或常量声明中的模式时,它只能包含通配符模式、标识符模式、可选模式或包含这些模式的其他元组模式。例如,以下代码无效,因为元组模式 `(x, 0)` 中的元素0是表达式模式: +您可以在函数调用表达式中使用初始化表达式来初始化类型的新实例。您还可以使用初始值设定项表达式来委托给超类的初始值设定项。 ```swift -let points = [(0, 0), (1, 0), (1, 1), (2, 0), (2, 1)] -// This code isn't valid. -for (x, 0) in points { - /* ... */ +class SomeSubClass: SomeSuperClass { + override init() { + // subclass initialization goes here + super.init() + } } ``` -包含单个元素的元组模式周围的括号不起作用。该模式与该单个元素类型的值相匹配。例如,以下内容是等效的: +与函数一样,初始化器可以用作值。例如: + +```swift +// Type annotation is required because String has multiple initializers. +let initializer: (Int) -> String = String.init +let oneTwoThree = [1, 2, 3].map(initializer).reduce("", +) +print(oneTwoThree) +// Prints "123" +``` +如果按名称指定类型,则可以访问该类型的初始值设定项,而无需使用初始值设定项表达式。在所有其他情况下,您必须使用初始化表达式。 + ```swift -let a = 2 // a: Int = 2 -let (a) = 2 // a: Int = 2 -let (a): Int = 2 // a: Int = 2 +let s1 = SomeType.init(data: 3) // Valid +let s2 = SomeType(data: 1) // Also valid + +let s3 = type(of: someValue).init(data: 7) // Valid +let s4 = type(of: someValue)(data: 5) // Error ``` -> Grammar of a tuple pattern: +> 初始化表达式的语法: > -> *tuple-pattern* → **`(`** *tuple-pattern-element-list*_?_ **`)`** \ -> *tuple-pattern-element-list* → *tuple-pattern-element* | *tuple-pattern-element* **`,`** *tuple-pattern-element-list* \ -> *tuple-pattern-element* → *pattern* | *identifier* **`:`** *pattern* +> *initializer-expression* → *postfix-expression* **`.`** **`init`** \ +> *initializer-expression* → *postfix-expression* **`.`** **`init`** **`(`** *argument-names* **`)`** -## 枚举案例模式 +### 显式成员表达式 -*枚举大小写模式* 与现有枚举类型的大小写匹配。枚举 case 模式出现在 `switch` 语句 case 标签以及 `if` 、 `while` 、 `guard` 和`for` - `in` 语句的 case 条件中。 +*显式成员表达式*允许访问命名类型、元组或模块的成员。它由项目与其成员标识符之间的句点 ( `.` ) 组成。 -如果您尝试匹配的枚举大小写具有任何关联值,则相应的枚举大小写模式必须指定一种元组模式,其中每个关联值都包含一个元素。有关使用`switch` 语句来匹配包含关联值的枚举情况的示例,请参阅 . +```swift +<#expression#>.<#member name#> +``` -枚举大小写模式还匹配包装在可选值中的该大小写的值。这种简化的语法允许您省略可选模式。请注意,由于 `Optional` 是作为枚举实现的,因此 `.none` 和 `.some` 可以与枚举类型的情况出现在同一开关中 +命名类型的成员被命名为类型声明或扩展的一部分。例如: ```swift -enum SomeEnum { case left, right } -let x: SomeEnum? = .left -switch x { -case .left: - print("Turn left") -case .right: - print("Turn right") -case nil: - print("Keep going straight") +class SomeClass { + var someProperty = 42 } -// Prints "Turn left" +let c = SomeClass() +let y = c.someProperty // Member access ``` -> Grammar of an enumeration case pattern: -> -> *enum-case-pattern* → *type-identifier*_?_ **`.`** *enum-case-name* *tuple-pattern*_?_ +元组的成员按照它们出现的顺序使用整数隐式命名,从零开始。例如: + +```swift +var t = (10, 20, 30) +t.0 = t.1 +// Now t is (20, 20, 30) +``` + + -## 可选图案 +模块的成员访问该模块的顶级声明。 -可选模式与包含在 `Optional` 枚举的 `some(Wrapped)` 情况中的值相匹配。可选模式由标识符模式组成,后面紧跟一个问号,并出现在与枚举案例模式相同的位置 +使用`dynamicMemberLookup`属性声明的类型包括在运行时查找的成员,如 中所述。 -由于可选模式是 `Optional`枚举案例模式的语法糖,因此以下内容是等效的: +为了区分名称仅因参数名称而不同的方法或初始化器, + +要区分名称仅因参数名称不同的方法或初始值设定项,请将参数名称包含在括号中,每个参数名称后跟一个冒号 `:` )。为没有名称的参数写入下划线 ( `_` )。要区分重载方法,请使用类型注释。例如: ```swift -let someOptional: Int? = 42 -// Match using an enumeration case pattern. -if case .some(let x) = someOptional { - print(x) +class SomeClass { + func someMethod(x: Int, y: Int) {} + func someMethod(x: Int, z: Int) {} + func overloadedMethod(x: Int, y: Int) {} + func overloadedMethod(x: Int, y: Bool) {} } +let instance = SomeClass() -// Match using an optional pattern. -if case let x? = someOptional { - print(x) -} +let a = instance.someMethod // Ambiguous +let b = instance.someMethod(x:y:) // Unambiguous + +let d = instance.overloadedMethod // Ambiguous +let d = instance.overloadedMethod(x:y:) // Still ambiguous +let d: (Int, Bool) -> Void = instance.overloadedMethod(x:y:) // Unambiguous ``` -可选模式提供了一种方便的方法来迭代 `for` - `in`语句中的可选值数组,仅对非 `nil` 元素执行循环体 +如果句点出现在行的开头,则它将被理解为显式成员表达式的一部分,而不是隐式成员表达式。例如,以下清单显示了分为几行的链式方法调用: ```swift -let arrayOfOptionalInts: [Int?] = [nil, 2, 3, nil, 5] -// Match only non-nil values. -for case let number? in arrayOfOptionalInts { - print("Found a \(number)") -} -// Found a 2 -// Found a 3 -// Found a 5 +let x = [10, 3, 20, 15, 4] + .sorted() + .filter { $0 > 5 } + .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`和其他编译指令之间,条件编译块可以包含隐式成员表达式,后跟零个或多个后缀,以形成后缀表达式。它还可以包含另一个条件编译块,或这些表达式和块的组合。 + +您可以在任何可以编写显式成员表达式的地方使用此语法,而不仅仅是在顶级代码中。 + +在条件编译块中, `#if` 编译指令的分支必须至少包含一个表达式。其他分支可以为空。 + + + + + + -> Grammar of an optional pattern: +> 显式成员表达式的语法: +> +> *explicit-member-expression* → *postfix-expression* **`.`** *decimal-digits* \ +> *explicit-member-expression* → *postfix-expression* **`.`** *identifier* *generic-argument-clause*_?_ \ +> *explicit-member-expression* → *postfix-expression* **`.`** *identifier* **`(`** *argument-names* **`)`** \ +> *explicit-member-expression* → *postfix-expression* *conditional-compilation-block* +> +> *argument-names* → *argument-name* *argument-names*_?_ \ +> *argument-name* → *identifier* **`:`** + + + + + +### 自我表达 + +后缀`self` 表达式由表达式或类型名称组成,后跟 `.self` 。它有以下几种形式: + +```swift +<#expression#>.self +<#type#>.self +``` + +第一种形式计算表达式的值。例如, `x.self` 计算结果为 `x` 。 + +第二种形式求值为*type*的值。使用此形式将类型作为值进行访问。例如,由于 `SomeClass.self` 计算结果为 `SomeClass` 类型本身,因此您可以将其传递给接受类型级参数的函数或方法。 + +> 后缀自我表达的语法: > -> *optional-pattern* → *identifier-pattern* **`?`** +> *postfix-self-expression* → *postfix-expression* **`.`** **`self`** -## 类型转换模式 +### 下标表达式 -有两种类型转换模式: `is` 模式和`as` 模式。 `is` 模式仅出现在`switch` 语句 case 标签中. `is` 和 `as` 模式具有以下形式: +*下标表达式*使用相应下标声明的 getter 和 setter 提供下标访问。它具有以下形式: ```swift -is <#type#> -<#pattern#> as <#type#> +<#expression#>[<#index expressions#>] ``` -如果运行时值的 `is` 与 `is` 模式与该值匹配 - 或者该类型的子类。 `is` 模式的行为类似于 `is` 运算符,因为它们都执行类型转换但丢弃返回的类型。 +为了计算下标表达式的值,需要调用表达式类型的下标 getter,并将索引表达式作为下标参数传递。为了设置它的值,以同样的方式调用下标设置器。 -如果运行时该值的类型与`as模` 式右侧指定的类型相同,则 `as` 模式与该值匹配 - 或者该类型的子类。如果匹配成功,则匹配值的类型将转换为 `as` 模式右侧指定的模式 + -有关使用 `switch` 语句将值与 `is` 和 `as` 模式进行匹配的示例,请参阅 . +有关下标声明的信息,请参阅 . -> Grammar of a type casting pattern: +> 下标表达式的语法: > -> *type-casting-pattern* → *is-pattern* | *as-pattern* \ -> *is-pattern* → **`is`** *type* \ -> *as-pattern* → *pattern* **`as`** *type* +> *subscript-expression* → *postfix-expression* **`[`** *function-call-argument-list* **`]`** + + + +### 强制值表达 -## 表达模式 +*强制值表达式*会解包您确定不是 `nil` 的可选值。它具有以下形式: + +```swift +<#expression#>! +``` -*表达式模式* 表示表达式的值。表达式模式仅出现在*switch* 语句 *case* 标签中 +如果表达式的值不是 `nil` ,则可选值将被解包并以相应的非可选类型返回。否则,会引发运行时错误。 -使用 Swift 标准库中的模式匹配运算符 ( `~=` ) 将表达式模式表示的表达式与输入表达式的值进行比较。如果`~=` 运算符返回`true` 则匹配成功。默认情况下, `~= ` 运算符使用`==`运算符比较相同类型的两个值。它还可以通过检查值是否包含在范围内来将值与值范围匹配,如以下示例所示。 +可以通过改变值本身或分配给值的成员之一来修改强制值表达式的展开值。例如: ```swift -let point = (1, 2) -switch point { -case (0, 0): - print("(0, 0) is at the origin.") -case (-2...2, -2...2): - print("(\(point.0), \(point.1)) is near the origin.") -default: - print("The point is at (\(point.0), \(point.1)).") +var x: Int? = 0 +x! += 1 +// x is now 1 + +var someDictionary = ["a": [1, 2, 3], "b": [10, 20]] +someDictionary["a"]![0] = 100 +// someDictionary is now ["a": [100, 2, 3], "b": [10, 20]] +``` + + + +> 强制值表达式的语法: +> +> *强制值表达式* → *后缀表达式* **`!`** + +### 可选链式表达式 + +*可选链表达式*提供了在后缀表达式中使用可选值的简化语法。它具有以下形式: + +```swift +<#expression#>? +``` + +后缀 `?` 运算符从表达式创建可选链表达式而不更改表达式的值。 + +可选链表达式必须出现在后缀表达式中,并且它们会导致后缀表达式以特殊方式进行计算。如果可选链表达式的值为 `nil` ,则后缀表达式中的所有其他操作都将被忽略,并且整个后缀表达式的计算结果为 `nil` 。如果可选链表达式的值不是 `nil` ,则可选链表达式的值将被展开并用于计算后缀表达式的其余部分。无论哪种情况,后缀表达式的值仍然是可选类型。 + +如果包含可选链表达式的后缀表达式嵌套在其他后缀表达式中,则只有最外面的表达式返回可选类型。在下面的示例中,当 `c `不为 `nil`时,其值将被展开并用于计算 `.property` ,其值用于计算 `.performAction()` 。整个表达式 `c?.property.performAction()`具有可选类型的值。 + +```swift +var c: SomeClass? +var result: Bool? = c?.property.performAction() +``` + + + +以下示例显示了上面示例的行为,而不使用可选链。 + +```swift +var result: Bool? +if let unwrappedC = c { + result = unwrappedC.property.performAction() } -// Prints "(1, 2) is near the origin." ``` -您可以重载`~=` 运算符以提供自定义表达式匹配行为。例如,您可以重写上面的示例,以将`point`表达式与点的字符串表示形式进行比较. +可以通过改变值本身或分配给值的成员之一来修改可选链表达式的展开值。如果可选链表达式的值为nil ,则不计算赋值运算符右侧的表达式。例如: ```swift -// Overload the ~= operator to match a string with an integer. -func ~= (pattern: String, value: Int) -> Bool { - return pattern == "\(value)" -} -switch point { -case ("0", "0"): - print("(0, 0) is at the origin.") -default: - print("The point is at (\(point.0), \(point.1)).") +func someFunctionWithSideEffects() -> Int { + return 42 // No actual side effects. } -// Prints "The point is at (1, 2)." +var someDictionary = ["a": [1, 2, 3], "b": [10, 20]] + +someDictionary["not here"]?[0] = someFunctionWithSideEffects() +// someFunctionWithSideEffects isn't evaluated +// someDictionary is still ["a": [1, 2, 3], "b": [10, 20]] + +someDictionary["a"]?[0] = someFunctionWithSideEffects() +// someFunctionWithSideEffects is evaluated and returns 42 +// someDictionary is now ["a": [42, 2, 3], "b": [10, 20]] ``` -> 表达式模式的语法: +> 可选链表达式的语法: > -> *expression-pattern* → *expression* +> *optional-chaining-expression* → *postfix-expression* **`?`** > 测试版软件: > -> 本文档包含有关正在开发的 API 或技术的初步信息。该信息可能会发生变化,并且根据本文档实现的软件应使用最终操作系统软件进行测试. +> 本文档包含有关正在开发的 API 或技术的初步信息。该信息可能会发生变化,并且根据本文档实现的软件应使用最终操作系统软件进行测试。. > -> 了解有关使用 [Apple 测试软件的](https://developer.apple.com/support/beta-software/)更多信息. +> 了解更多关于使用 [Apple's beta software](https://developer.apple.com/support/beta-software/). - From 8324a51766bb945930b9b96362c8f7de9babd863 Mon Sep 17 00:00:00 2001 From: King <66349714+king-open@users.noreply.github.com> Date: Sun, 20 Oct 2024 03:59:51 +0800 Subject: [PATCH 10/14] =?UTF-8?q?=E7=BF=BB=E8=AF=91=E5=AE=8C=20Expressions?= =?UTF-8?q?.md=20=E8=BF=99=E7=AF=87?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../ReferenceManual/Expressions.md | 1675 +++-------------- 1 file changed, 261 insertions(+), 1414 deletions(-) diff --git a/swift-6-beta.docc/ReferenceManual/Expressions.md b/swift-6-beta.docc/ReferenceManual/Expressions.md index 5333fbdff..83e576c07 100644 --- a/swift-6-beta.docc/ReferenceManual/Expressions.md +++ b/swift-6-beta.docc/ReferenceManual/Expressions.md @@ -2,311 +2,181 @@ 访问、修改和分配值。 -在 Swift 中,有四种表达式:前缀表达式、中缀表达式、主表达式和后缀表达式。计算表达式会返回一个值、导致副作用,或两者兼而有之。 +Swift 中存在四种表达式:前缀表达式,中缀表达式,基本表达式和后缀表达式。表达式在返回一个值的同时还可以引发副作用。 -前缀和中缀表达式允许您将运算符应用于较小的表达式。主表达式在概念上是最简单的表达式,它们提供了一种访问值的方法。后缀表达式与前缀和中缀表达式一样,允许您使用后缀构建更复杂的表达式,例如函数调用和成员访问。下面各节详细描述了每种表达式。 +通过前缀表达式和中缀表达式可以对简单表达式使用各种运算符。基本表达式从概念上讲是最简单的一种表达式,它是一种访问值的方式。后缀表达式则允许你建立复杂的表达式,例如函数调用和成员访问。每种表达式都在下面有详细论述。 -> 表达式的语法: +> 表达式语法: > -> *expression* → *try-operator*_?_ *await-operator*_?_ *prefix-expression* *infix-expressions*_?_ \ +> *表达式语法* → *try 运算符*_?_ *await运算符*_?_ *前缀表达式* *中缀表达式*_?_ \ ## 前缀表达式 -前缀表达式将可选的前缀运算符与表达式结合起来。前缀运算符采用一个参数,即它们后面的表达式。 +前缀表达式由可选的前缀运算符和表达式组成。前缀运算符只接收一个参数,表达式则紧随其后。 -有关这些运算符的行为的信息,请参阅。 +关于这些运算符的更多信息,请参阅。 -有关 Swift 标准库提供的运算符的信息,请参阅[Operator Declarations](https://developer.apple.com/documentation/swift/operator_declarations)。 +关于 Swift 标准库提供的运算符的更多信息,请参阅[Operator Declarations](https://developer.apple.com/documentation/swift/operator_declarations)。 -> 前缀表达式的语法: +> 前缀表达式语法: > -> *prefix-expression* → *prefix-operator*_?_ *postfix-expression* \ -> *prefix-expression* → *in-out-expression* +> *前缀表达式* → *前缀运算符*_?_ *后缀表达式* \ +> *前缀表达式* → *输入输出表达式* ### 输入输出表达式 -输入输出表达式标记作为输入输出参数传递给函数调用表达式的变量。 +输入输出表达式 将函数调用表达式传入的变量标记为输入输出实参。 ```swift -&<#expression#> +&<#表达式#> ``` -有关输入输出参数的更多信息以及查看示例,请参阅. +更多关于输入输出形参的信息和例子,请参阅. -在需要指针的上下文中提供非指针参数时,也会使用输入输出表达式,如 中所述。 +输入输出表达式也可以用于将非指针实参传入到需要指针的上下文中,如 中所述。 -> 输入输出表达式的语法: +> 输入输出表达式语法: > -> *in-out-expression* → **`&`** *primary-expression* +> *输入输出表达式* → **`&`** *标识符* -### 尝试操作员 +### Try 运算符 - try 表达式由`try` 运算符后跟一个可能引发错误的表达式组成。它具有以下形式: + try 表达式由`try` 运算符加上紧随其后的可抛出错误的表达式组成,形式如下: ```swift -try <#expression#> +try <#表达式#> ``` -`try` 表达式的值是 *表达式*的值. +`try` 表达式的返回值是该*表达式*的值。 -可选的 try 表达式由`try?` 组成。运算符后跟可能引发错误的表达式。它具有以下形式: +可选的 try 表达式由`try?` 运算符加上紧随其后的可抛出错误的表达式组成,形式如下: ```swift -try? <#expression#> +try? <#表达式#> ``` -如果表达式没有抛出错误,则可选尝试表达式的值是包含表达式值的可选值。否则,可选尝试表达式的值为 `nil`。 - -强制尝试表达式由`try!` 组成。运算符后跟可能引发错误的表达式。它具有以下形式: - +如果表达式没有抛出错误,可选 try 表达式的返回值是可选的该表达式的值,否则,返回值为 `nil`。 +强制 try 表达式由 `try!` 运算符加上紧随其后的可抛出错误的表达式组成,形式如下: ```swift -try! <#expression#> +try! <#表达式#> ``` -强制尝试表达式的值是表达式的值。如果表达式抛出错误,则会产生运行时错误。 +强制 try 表达式的返回值是该表达式的值。如果该表达式抛出了错误,将会引发运行时错误。 -当中缀运算符左侧的表达式标有 `try` 时, `try?` ,或者 `try!` ,该运算符适用于整个中缀表达式。也就是说,您可以使用括号来明确运算符应用程序的范围。 +在中缀运算符左侧的表达式被标记上 `try`、`try?` 或者 `try!` 时,这个运算符对整个中缀表达式都产生作用。也就是说,你可以使用括号来明确运算符的作用范围。 ```swift -// try applies to both function calls +// try 对两个函数调用都产生作用 sum = try someThrowingFunction() + anotherThrowingFunction() -// try applies to both function calls +// try 对两个函数调用都产生作用 sum = try (someThrowingFunction() + anotherThrowingFunction()) -// Error: try applies only to the first function call +// 错误:try 只对第一个函数调用产生作用 sum = (try someThrowingFunction()) + anotherThrowingFunction() ``` - - -`try` 表达式不能出现在中缀运算符的右侧,除非中缀运算符是赋值运算符或者 `try`表达式括在括号中。 - - - +如果表达式同时包含`try`和`await`运算符,则`try`运算符必须在前面。 -如果表达式同时包含`try`和`await`运算符,则`try`运算符必须首先出现。 +更多关于`try`、`try?`的示例,并 `try!` 的信息,以及该如何使用的例子,请参阅 . - - -有关更多信息并查看如何使用`try`、`try?`的示例,并 `try! ` 请参阅 . - -> try 表达式的语法: +> try 表达式语法: > -> *try-operator* → **`try`** | **`try`** **`?`** | **`try`** **`!`** +> *try-运算符* → **`try`** | **`try`** **`?`** | **`try`** **`!`** -### 等待接线员 +### Await 运算符 -*wait* 表达式由`await`运算符后跟一个使用异步操作结果的表达式组成。它具有以下形式 +*await* 表达式由`await` 运算符加上紧随其后的异步操作结果的表达式。形式如下: ```swift -await <#expression#> +await <#表达式#> ``` -`await`表达式的值是expression的值。标有await表达式称为 *潜在挂起点* 。异步函数的执行可以在每个用 `await`标记的表达式处暂停。此外,并发代码的执行永远不会在任何其他点暂停。这意味着潜在挂起点之间的代码可以安全地更新需要暂时破坏不变量的状态,前提是它在下一个潜在挂起点之前完成更新。 +`await`表达式返回值就是该*表达式*的值。被 `await` 标记的表达式被称为潜在的暂停点。 异步函数的执行可以在每个标记 `await` 的表达式的位置暂停。除此之外,并发代码的执行永远不会在其他位置暂停。这意味着在潜在暂停点之间的代码可以暂时打破不变量的状态进行安全更新,只要更新在下一个潜在暂停点之前完成。 +`await` 表达式只能在异步的上下文中出现,比如传入 `async(priority:operation:)` 函数的尾随闭包中。它不能在`defer` 语句的闭包中,或者在同步函数的自动闭包中出现。 - -`await` 表达式只能出现在异步上下文中,例如传递给 `async(priority:operation:)`函数的尾随闭包。它不能出现在defer语句的主体中,也不能出现在同步函数类型的自动闭包中。 - -当中缀运算符左侧的表达式用`await`运算符标记时,该运算符适用于整个中缀表达式。也就是说,您可以使用括号来明确运算符应用程序的范围。 +在中缀运算符左侧的表达式被标记上 `await` 运算符时,这个运算符对整个中缀表达式都产生作用。也就是说,你可以使用括号来明确运算符的作用范围。 ```swift -// await applies to both function calls +// await 对两个函数调用都产生作用 sum = await someAsyncFunction() + anotherAsyncFunction() -// await applies to both function calls +// await 对两个函数调用都产生作用 sum = await (someAsyncFunction() + anotherAsyncFunction()) -// Error: await applies only to the first function call +// 错误:await 只对第一个函数调用产生作用 sum = (await someAsyncFunction()) + anotherAsyncFunction() ``` +`await`表达式不能出现在中缀运算符的的右侧,除非中缀运算符是赋值运算符或者`await` 表达式是被圆括号括起来的。 - +如果表达式中同时包含 `try` 和 `await` 运算符,`try` 运算符必须在前面。 -`await`表达式不能出现在中缀运算符的右侧,除非中缀运算符是赋值运算符或者将await表达式括在括号中。 - - - -如果表达式同时包含 `await`和try运算符,则try运算符必须首先出现。 - - - -> 等待表达的语法: +> Await 表达式语法: > -> *等待运算符* → **`await`** +> *await运算符* → **`await`** ## 中缀表达式 -*中缀表达式* 将中缀二元运算符与其作为其左侧和右侧参数的表达式组合起来。它具有以下形式: +*中缀表达式*由中缀运算符和左右参数表达式组成。形式如下: ```swift -<#left-hand argument#> <#operator#> <#right-hand argument#> +<#左侧参数#> <#中缀运算符#> <#右侧参数#> ``` -有关这些运算符的行为的信息,请参阅 . +关于这些运算符的更多信息,请参阅 . -有关 Swift 标准库提供的运算符的信息,请参阅 [Operator Declarations](https://developer.apple.com/documentation/swift/operator_declarations). - - +关于 Swift 标准库提供的运算符的更多信息,请参阅 [Operator Declarations](https://developer.apple.com/documentation/swift/operator_declarations). -> 注意:在解析时,由中缀运算符组成的表达式表示为平面列表。通过应用运算符优先级将该列表转换为树。例如,表达式2 + 3 * 5最初被理解为五个项目2 、 + 、 3 、 *和5的平面列表。此过程将其转换为树 (2 + (3 * 5))。 +> 注意:在解析时,一个中缀表达式将作为一个扁平列表表示,然后根据运算符的优先级,再进一步进行组合。例如,`2 + 3 * 5` 首先被看作具有五个元素的列表,即 `2`、`+`、`3`、`*`、`5`,随后根据运算符优先级组合为 `(2 + (3 * 5))`。 -> 中缀表达式的语法: +> 中置表达式语法 > -> *infix-expression* → *infix-operator* *prefix-expression* \ -> *infix-expression* → *assignment-operator* *try-operator*_?_ *await-operator*_?_ *prefix-expression* \ -> *infix-expression* → *conditional-operator* *try-operator*_?_ *await-operator*_?_ *prefix-expression* \ -> *infix-expression* → *type-casting-operator* \ -> *infix-expressions* → *infix-expression* *infix-expressions*_?_ +> *中置表达式 * → *中置运算符* *前缀表达式* \ +> *中置表达式 * → *赋值运算符* *try 运算符*_?_ *await运算符*_?_ *前缀表达式* \ +> *中置表达式 * → *条件运算符* *条件运算符 try运算符*_?_ *await运算符*_?_ * 前缀表达式* \ +> *中置表达式 * → *类型转换运算符* \ +> *中置表达式 * → *中置表达式* *中置表达式列表*_?_ ### 赋值运算符 -*赋值运算符* 为给定表达式设置新值。它具有以下形式: +*赋值表达式*会为某个给定的表达式赋值,形式如下; ```swift -<#expression#> = <#value#> +<#表达#> = <#值#> ``` -*表达式* 的值设置为通过计算*value* 获得的值。如果表达式是元组,则值必须是具有相同元素数量的元组。 (允许嵌套元组。)从值的每个部分到表达式的相应部分执行赋值。例如: +右边的值会被赋值给左边的表达式。如果左边表达式是一个元组,那么右边必须是一个具有同样元素个数的元组。(嵌套元组也是允许的。)右边的值中的每一部分都会被赋值给左边的表达式中的相应部分。例如: ```swift (a, _, (b, c)) = ("test", 9.45, (12, 3)) -// a is "test", b is 12, c is 3, and 9.45 is ignored +// a 为 "test",b 为 12,c 为 3,9.45 会被忽略 ``` - - - 赋值运算符不返回任何值。 -> 赋值运算符的语法: +> 赋值运算符语法 > > *赋值运算符* → **`=`** ### 三元条件运算符 -*三元条件运算符*根据条件值计算两个给定值之一。它具有以下形式: +*三元条件运算符*会根据条件来对两个给定表达式中的一个进行求值,形式如下: ```swift -<#condition#> ? <#expression used if true#> : <#expression used if false#> +<#条件#> ? <#表达式(条件为真则使用)#> : <#表达式(条件为假则使用) #> ``` -如果*条件*计算结果为`true` ,则条件运算符计算第一个表达式并返回其值。否则,它计算第二个表达式并返回其值。不计算未使用的表达式。 +如果条件为真,那么对第一个表达式进行求值并返回结果。否则,对第二个表达式进行求值并返回结果。未使用的表达式不会进行求值。 -有关使用三元条件运算符的示例,请参阅文档: . +关于使用三元条件运算符的例子,请参阅: . -> 条件运算符的语法: +> 三元条件运算符语法 > -> *条件运算符* → **`?`** *表达* **`:`** +> *三元条件运算符* → **`?`** *表达* **`:`** ### 类型转换运算符 @@ -315,88 +185,38 @@ sum = (await someAsyncFunction()) + anotherAsyncFunction() 它们具有以下形式: ```swift -<#expression#> is <#type#> -<#expression#> as <#type#> -<#expression#> as? <#type#> -<#expression#> as! <#type#> +<#表达式#> is <#类型#> +<#表达式#> as <#类型#> +<#表达式#> as? <#类型#> +<#表达式#> as! <#类型#> ``` -`is`运算符在运行时检查表达式是否可以转换为指定类型。如果*表达式*可以转换为指定*类型*,则返回`true` ;否则,返回`false` 。 - - - - +`is` 运算符在运行时检查表达式能否向下转化为指定的类型,如果可以则返回 `ture`,否则返回 `false`。 -当在编译时已知转换始终成功时,`as`运算符会执行转换,例如向上转换或桥接。向上转换允许您使用表达式作为其类型的超类型的实例,而无需使用中间变量。以下方法是等效的: +`as` 运算符在编译时执行向上转换和桥接。向上转换可将表达式转换成父类的实例而无需使用任何中间变量。以下表达式是等价的: ```swift func f(_ any: Any) { print("Function for Any") } func f(_ int: Int) { print("Function for Int") } let x = 10 f(x) -// Prints "Function for Int" +// 打印 "Function for Int" let y: Any = x f(y) -// Prints "Function for Any" +// 打印 "Function for Any" f(x as Any) -// Prints "Function for Any" +// 打印 "Function for Any" ``` - - -桥接允许您使用`Swift` 标准库类型(例如String的表达式作为其相应的基础类型(例如NSString ,而无需创建新实例。有关桥接的更多信息,请参阅[Working with Foundation Types](https://developer.apple.com/documentation/swift/imported_c_and_objective_c_apis/working_with_foundation_types). +桥接可将 Swift 标准库中的类型(例如 `String`)作为一个与之相关的 Foundation 类型(例如 `NSString`)来使用,而不需要新建一个实例。关于桥接的更多信息,请参阅 [Working with Foundation Types](https://developer.apple.com/documentation/swift/imported_c_and_objective_c_apis/working_with_foundation_types). -`as?`运算符执行表达式到指定类型的条件转换。 `as?`运算符返回指定类型的可选值。在运行时,如果转换成功,则将表达式的值包装在可选值中并返回;否则,返回值为`nil` 。如果强制转换为指定类型肯定会失败或一定会成功,则会引发编译时错误。 +`as?` 运算符有条件地执行类型转换,返回目标类型的可选值。在运行时,如果转换成功,返回的可选值将包含转换后的值,否则返回 nil。如果在编译时就能确定转换一定会成功或是失败,则会导致编译报错。 -`as!`运算符将表达式强制转换为指定类型。 `as!`运算符返回指定类型的值,而不是可选类型。如果转换失败,则会引发运行时错误。 `x as! T`与 `(x as? T)!` 。 +as! 运算符执行强制类型转换,返回目标类型的非可选值。如果转换失败,则会导致运行时错误。表达式 `x as! T` 效果等同于 `(x as? T)!`。 -有关类型转换的更多信息以及查看使用类型转换运算符的示例,请参阅. +关于类型转换的更多内容和例子,请参阅. > 类型转换运算符的语法: > @@ -405,9 +225,9 @@ f(x as Any) > *类型转换运算符* → **`as`** **`?`** *类型* \ > *类型转换运算符* → **`as`** **`!`** *类型* -## 主要表达 +## 基本表达式 -*初级表达式*是最基本的表达式。它们可以单独用作表达式,也可以与其他标记组合以构成前缀表达式、中缀表达式和后缀表达式。 +*基本表达式*是最基本的表达式。它们可以单独使用,也可以跟前缀表达式、中置表达式、后缀表达式组合使用。 > 基本表达式的语法: > @@ -426,22 +246,10 @@ f(x as Any) > *primary-expression* → *selector-expression* \ > *primary-expression* → *key-path-string-expression* - - - -### 文字表达 +### 字面量表达式 -文字表达式由普通文字(例如字符串或数字)、数组或字典文字或游乐场文字组成 +*字面量表达式*可由普通字面量(例如字符串或者数字),字典或者数组字面量,或者下面列表中的特殊字面量组成: > Note: > Prior to Swift 5.9, @@ -462,67 +270,40 @@ f(x as Any) > [`function()`](https://developer.apple.com/documentation/swift/function()), > and [`line()`](https://developer.apple.com/documentation/swift/line()). - - -*数组文字*是值的有序集合。它具有以下形式: +数组字面量是值的有序集合,形式如下: ```swift -[<#value 1#>, <#value 2#>, <#...#>] +[<#值 1#>, <#值 2#>, <#...#>] ``` -数组中的最后一个表达式后面可以跟一个可选的逗号。数组文字的值具有类型`[T]` ,其中T是其中表达式的类型。如果存在多种类型的表达式,则`T` 是它们最接近的公共超类型。空数组文字使用一对空方括号编写,可用于创建指定类型的空数组。 +数组中的最后一个表达式可以紧跟一个逗号。数组字面量的类型是 `[T]`,这个 `T` 就是数组中元素的类型。如果数组中包含多种类型,`T` 则是跟这些类型最近的的公共父类型。空数组字面量由一组方括号定义,可用来创建特定类型的空数组。 ```swift var emptyArray: [Double] = [] ``` - - - -*字典文字* 是键值对的无序集合。它具有以下形式: +字典字面量是一个包含无序键值对的集合,形式如下: ```swift -[<#key 1#>: <#value 1#>, <#key 2#>: <#value 2#>, <#...#>] +[<#键 1#>: <#值 1#>, <#键 2#>: <#值 2#>, <#...#>] ``` -字典中的最后一个表达式后面可以跟一个可选的逗号。字典文字的值具有类型`[Key: Value]` ,其中 `Key`是其键表达式的类型, `Value` 是其值表达式的类型。如果存在多种类型的表达式,则`Key`和`Value`是其各自值最接近的公共超类型。空字典文字被写为一对括号 `( [:] )` 内的冒号,以将其与空数组文字区分开。您可以使用空字典文字来创建指定键和值类型的空字典文字。 +字典中的最后一个表达式可以紧跟一个逗号。字典字面量的类型是 `[Key : Value]`,`Key` 表示键的类型,`Value` 表示值的类型。如果字典中包含多种类型,那么 `Key` 表示的类型则为所有键最接近的公共父类型,`Value` 与之相似。一个空的字典字面量由方括号中加一个冒号组成(`[:]`),从而与空数组字面量区分开,可以使用空字典字面量来创建特定类型的字典。 ```swift var emptyDictionary: [String: Double] = [:] ``` - - -Xcode 使用 *Playground* 文字在程序编辑器中创建颜色、文件或图像的交互式表示。 Xcode 之外的纯文本 Playground 文字使用特殊的文字语法表示。 +Xcode 使用 playground 字面量对程序编辑器中的颜色、文件或者图片创建可交互的展示。在 Xcode 之外的空白文本中,playground 字面量使用一种特殊的字面量语法来展示。 -有关在 Xcode 中使用 Playground 文字的信息,请参阅 Xcode 帮助中[Add a color, file, or image literal](https://help.apple.com/xcode/mac/current/#/dev4c60242fc) +更多关于在 Xcode 中使用 playground 字面量的信息,请参阅 [Add a color, file, or image literal](https://help.apple.com/xcode/mac/current/#/dev4c60242fc) -> 文字表达式的语法: +> 字面量表达式语法: > -> *literal-expression* → *literal* \ -> *literal-expression* → *array-literal* | *dictionary-literal* | *playground-literal* +> *字面量表达式* → *字面量* \ +> *字面量表达式* → *数组字面量* | *字典字面量* | *练习场字面量* > -> *array-literal* → **`[`** *array-literal-items*_?_ **`]`** \ +> *字面量表达式* → **`[`** *array-literal-items*_?_ **`]`** \ > *array-literal-items* → *array-literal-item* **`,`**_?_ | *array-literal-item* **`,`** *array-literal-items* \ > *array-literal-item* → *expression* > @@ -534,25 +315,21 @@ Xcode 使用 *Playground* 文字在程序编辑器中创建颜色、文件或图 > *playground-literal* → **`#fileLiteral`** **`(`** **`resourceName`** **`:`** *expression* **`)`** \ > *playground-literal* → **`#imageLiteral`** **`(`** **`resourceName`** **`:`** *expression* **`)`** -### 自我表达 +### Self 表达式 -`self`表达式是对当前类型或它所在类型的实例的显式引用。它有以下几种形式: +`self`表达式是对当前类型或者当前实例的显式引用,它有如下形式: ```swift self -self.<#member name#> -self[<#subscript index#>] -self(<#initializer arguments#>) -self.init(<#initializer arguments#>) +self.<#成员名称#> +self[<#下标索引#>] +self(<#构造器参数#>) +self.init(<#构造器参数#>) ``` - - -在初始值设定项、下标或实例方法中, `self`指的是它出现的类型的当前实例。在类型方法中, `self`指的是它出现的当前类型。 +如果在构造器、下标、实例方法中,`self` 引用的是当前类型的实例。在一个类型方法中,`self` 引用的是当前的类型。 -`self`表达式用于在访问成员时指定作用域,当作用域中存在另一个同名变量(例如函数参数)时,可以消除歧义。例如: +当访问成员时,`self` 可用来区分重名变量,例如函数的参数: ```swift class SomeClass { @@ -562,21 +339,7 @@ class SomeClass { } } ``` - - - -在值类型的变异方法中,您可以将该值类型的新实例分配给 `self` 。例如: +在 `mutating` 方法中,你可以对 `self` 重新赋值: ```swift struct Point { @@ -587,54 +350,35 @@ struct Point { } ``` - - - - -> 自我表达的语法: +> Self 表达式语法: > -> *self-expression* → **`self`** | *self-method-expression* | *self-subscript-expression* | *self-initializer-expression* +> *self表达式* → **`self`** | *self表达式* | *self下标表达式* | *self构造表达式* > -> *self-method-expression* → **`self`** **`.`** *identifier* \ -> *self-subscript-expression* → **`self`** **`[`** *function-call-argument-list* **`]`** \ -> *self-initializer-expression* → **`self`** **`.`** **`init`** +> *self方法表达式* → **`self`** **`.`** *.标识符* \ +> *self下标表达式* → **`self`** **`[`** *函数调用参数表* **`]`** \ +> *self构造器表达式* → **`self`** **`.`** **`init`** -### 超类表达式 +### 父类表达式 -*超类表达式*允许类与其超类交互。它具有以下形式之一: +*父类表达式*可以使我们在某个类中访问它的父类,它有如下形式: ```swift -super.<#member name#> -super[<#subscript index#>] -super.init(<#initializer arguments#>) +super.<#成员名称#> +super[<#下标索引#>] +super.init(<#构造器参数#>) ``` -第一种形式用于访问超类的成员。第二种形式用于访问超类的下标实现。第三种形式用于访问超类的初始值设定项。 +第一种形式用来访问父类的某个成员,第二种形式用来访问父类的下标,第三种形式用来访问父类的构造器。 -子类可以在其成员、下标和初始化器的实现中使用超类表达式,以利用其超类中的实现。 +子类可以通过父类表达式在它们的成员、下标和构造器中使用父类中的实现。 -> 超类表达式的语法: +> 父类表达式语法: > -> *superclass-expression* → *superclass-method-expression* | *superclass-subscript-expression* | *superclass-initializer-expression* +> *父类表达式* → *父类方法表达式* | *父类下标表达式* | *父类构造器表达式* > -> *superclass-method-expression* → **`super`** **`.`** *identifier* \ -> *superclass-subscript-expression* → **`super`** **`[`** *function-call-argument-list* **`]`** \ -> *superclass-initializer-expression* → **`super`** **`.`** **`init`** +> *父类方法表达式* → **`super`** **`.`** *标识符* \ +> *父类下标表达式* → **`super`** **`[`** *函数调用参数表* **`]`** \ +> *父类构造器表达式* → **`super`** **`.`** **`init`** ### 条件表达式 @@ -699,7 +443,7 @@ let number = if someCondition { 10 as Double } else { 12.34 } ### 闭包表达式 -闭包表达式创建一个闭包,在其他编程语言中也称为*lambda*或匿名函数。与函数声明一样,闭包包含语句,并且它从其封闭范围捕获常量和变量。它具有以下形式: +闭包表达式会创建一个闭包,在其他语言中也叫 *lambda* 或匿名函数。跟函数一样,闭包包含了待执行的代码,不同的是闭包还会捕获所在环境中的常量和变量。它的形式如下: ```swift { (<#parameters#>) -> <#return type#> in @@ -707,9 +451,9 @@ let number = if someCondition { 10 as Double } else { 12.34 } } ``` -这些参数与函数声明中的参数具有相同的形式,如。 +闭包的参数声明形式跟函数一样,请参阅。 -在闭包表达式中写入`throws`或`async`显式地将闭包标记为抛出或异步。 +在闭包表达式中写入 `throws` 或 `async` 将显式地将闭包标记为丢掷或异步的。 ```swift { (<#parameters#>) async throws -> <#return type#> in @@ -717,19 +461,17 @@ let number = if someCondition { 10 as Double } else { 12.34 } } ``` -如果闭包的主体包含一个`throws`语句或一个未嵌套在具有详尽错误处理的`do`语句内的`try`表达式,则该闭包被理解为抛出。如果抛出闭包仅抛出单一类型的错误,则该闭包被理解为抛出该错误类型;否则,它被理解为抛出 `any Error` 。同样,如果主体包含`await`表达式,则它被理解为异步的。 +如果闭包的主体中含有 try 表达式,则认为该闭包会引发异常。同理,若闭包主体含有 await 表达式,则认为该闭包是异步的。 -有几种特殊的形式可以让闭包写得更简洁: +闭包还有几种特殊的形式,能让闭包使用起来更加简洁: - +- 闭包可以省略它的参数和返回值的类型。如果省略了参数名和所有的类型,也要省略 `in` 关键字。如果被省略的类型无法被编译器推断,那么就会导致编译错误。 -- 闭包可以省略其参数类型、返回类型或两者。如果省略参数名称和两种类型,请省略语句前的`in`关键字。如果无法推断省略的类型,则会引发编译时错误。 +- 闭包可以省略参数名,参数会被隐式命名为 `$` 加上其索引位置,例如 `$0`、`$1`、`$2` 分别表示第一个、第二个、第三个参数,以此类推。 -- 闭包可以省略其参数的名称。然后,其参数隐式命名为`$`后跟其位置: `$0` 、 `$1 ` 、 `$2`等。 +- 如果闭包中只包含一个表达式,那么该表达式的结果就会被视为闭包的返回值。表达式结果的类型也会被推断为闭包的返回类型。 -- 仅包含单个表达式的闭包被理解为返回该表达式的值。对周围表达式执行类型推断时,也会考虑该表达式的内容。 - -以下闭包表达式是等效的: +下面几个闭包表达式是等价的: ```swift myFunction { (x: Int, y: Int) -> Int in @@ -745,38 +487,19 @@ myFunction { return $0 + $1 } myFunction { $0 + $1 } ``` - - -有关将闭包作为参数传递给函数的信息,请参阅 . +关于如何将闭包作为参数来传递的内容,请参阅 . -闭包表达式可以在不存储在变量或常量中的情况下使用,例如当您立即使用闭包作为函数调用的一部分时。上面代码中传递给`myFunction`闭包表达式就是这种立即使用的示例。因此,闭包表达式是转义还是非转义取决于表达式的周围上下文。如果立即调用闭包表达式或作为非转义函数参数传递,则闭包表达式是非转义的。否则,闭包表达式就会转义。 +使用闭包表达式时,可以不必将其存储在一个变量或常量中,例如作为函数调用的一部分来立即使用一个闭包。在上面的例子中,传入 `myFunction` 的闭包表达式就是这种立即使用类型的闭包。因此,一个闭包是否逃逸与其使用时的上下文相关。一个会被立即调用或者作为函数的非逃逸参数传递的闭包表达式是非逃逸的,否则,这个闭包表达式是逃逸的。 -有关转义闭包的更多信息,请参阅文档:. +关于逃逸闭包的内容,请参阅:. #### 捕获列表 -默认情况下,闭包表达式从其周围范围捕获常量和变量,并对这些值进行强引用。您可以使用捕获列表来显式控制如何在闭包中捕获值。 +默认情况下,闭包表达式从其周围范围捕获常量和变量,并使用强引用指向它们。你可以通过一个捕获列表来显式指定它的捕获行为。 -捕获列表写为以逗号分隔的表达式列表,并用方括号括起来,位于参数列表之前。如果使用捕获列表,则即使省略参数名称、参数类型和返回类型,也必须使用`in`关键字。 +捕获列表在参数列表之前,由中括号括起来,里面是由逗号分隔的一系列表达式。一旦使用了捕获列表,就必须使用 `in` 关键字,即使省略了参数名、参数类型和返回类型。 -捕获列表中的条目在创建闭包时被初始化。对于捕获列表中的每个条目,常量被初始化为周围范围中具有相同名称的常量或变量的值。例如,在下面的代码中, `a`包含在捕获列表中,但`b`不包含在捕获列表中,这使它们具有不同的行为。 +捕获列表中的项会在闭包创建时被初始化。每一项都会用闭包附近作用域中的同名常量或者变量的值初始化。例如下面的代码示例中,捕获列表包含 `a` 而不包含 `b`,这将导致这两个变量具有不同的行为。 ```swift var a = 0 @@ -788,38 +511,12 @@ let closure = { [a] in a = 10 b = 10 closure() -// Prints "0 10" +// 打印 "0 10" ``` - - -有两种不同的东西,名为`a` ,周围作用域中的变量和闭包作用域中的常量,但只有一个名为`b` 变量。创建闭包时,内部作用域中的`a`会使用外部作用域中a的值进行初始化,但它们的值不会以任何特殊方式连接。这意味着外部作用域中a值的更改不会影响内部作用域中`a`的值,闭包内部a的更改也不会影响闭包外部a的值。相比之下,只有一个名为b的变量——外部作用域中的`b`因此来自闭包内部或外部的更改在两个地方都可见。 - - - -当捕获的变量的类型具有引用语义时,这种区别不可见。例如,下面的代码中有两个名为`x`的东西,外部作用域中的变量和内部作用域中的常量,但由于引用语义,它们都引用同一个对象。 +如果闭包捕获的值具有引用语义则有所不同。例如,下面示例中,有两个变量 `x`,一个在闭包外,一个在闭包内,由于它们的值是引用语义,虽然这是两个不同的变量,它们却都引用着同一实例。 ```swift class SimpleClass { @@ -836,145 +533,32 @@ y.value = 10 closure() // Prints "10 10" ``` - - - - - - - - - -如果表达式值的类型是类,则可以使用`weak`或`unowned`标记捕获列表中的表达式,以捕获对该表达式值的弱或无主引用。 +如果捕获列表中的值是类类型,你可以使用 `weak` 或者 `unowned` 来修饰它,闭包会分别用弱引用和无主引用来捕获该值。 ```swift -myFunction { print(self.title) } // implicit strong capture -myFunction { [self] in print(self.title) } // explicit strong capture -myFunction { [weak self] in print(self!.title) } // weak capture -myFunction { [unowned self] in print(self.title) } // unowned capture +myFunction { print(self.title) } // 隐式强引用捕获 +myFunction { [self] in print(self.title) } // 显式强引用捕获 +myFunction { [weak self] in print(self!.title) } // 弱引用捕获 +myFunction { [unowned self] in print(self.title) } // 无主引用捕获 ``` - - - -您还可以将任意表达式绑定到捕获列表中的命名值。创建闭包时将对表达式求值,并以指定的强度捕获该值。例如: +在捕获列表中,也可以将任意表达式的值绑定到一个常量上。该表达式会在闭包被创建时进行求值,闭包会按照指定的引用类型来捕获表达式的值。例如: ```swift -// Weak capture of "self.parent" as "parent" +// 以弱引用捕获 self.parent 并赋值给 parent myFunction { [weak parent = self.parent] in print(parent!.title) } ``` +关于闭包表达式的更多信息和例子,请参阅 . +关于捕获列表的更多信息和例子,请参阅 . - - -有关闭包表达式的更多信息和示例,请参阅文档: . -关捕获列表的更多信息和示例,请参阅文档:. - - - -> 闭包表达式的语法: +> 闭包表达式语法 > -> *closure-expression* → **`{`** *attributes*_?_ *closure-signature*_?_ *statements*_?_ **`}`** +> *闭包表达式* → **`{`** *特性*_?_ *闭包签名*_?_ *语句*_?_ **`}`** > -> *closure-signature* → *capture-list*_?_ *closure-parameter-clause* **`async`**_?_ *throws-clause*_?_ *function-result*_?_ **`in`** \ -> *closure-signature* → *capture-list* **`in`** +> *闭包签名* → *捕获列表*_?_ *闭包形参子句* **`async`**_?_ *throws*_?_ *函数结果*_?_ **`in`** \ +> *闭包签名 * → *捕获列表* **`in`** > -> *closure-parameter-clause* → **`(`** **`)`** | **`(`** *closure-parameter-list* **`)`** | *identifier-list* \ -> *closure-parameter-list* → *closure-parameter* | *closure-parameter* **`,`** *closure-parameter-list* \ +> *闭包形参子句* → **`(`** **`)`** | **`(`** *闭包形参列表* **`)`** | *标识符列表* \ +> *闭包形参列表* → *闭包形参* | *闭包形参* **`,`** *闭包形参列表* \ > *closure-parameter* → *closure-parameter-name* *type-annotation*_?_ \ > *closure-parameter* → *closure-parameter-name* *type-annotation* **`...`** \ > *closure-parameter-name* → *identifier* @@ -988,10 +572,10 @@ myFunction { [weak parent = self.parent] in print(parent!.title) } ### 隐式成员表达式 -*隐式成员*表达式是在类型推断可以确定隐含类型的上下文中访问类型成员(例如枚举情况或类型方法)的缩写方式。它具有以下形式: +若类型可被推断出来,可以使用*隐式成员表达式*来访问某个类型的成员(例如某个枚举成员或某个类型方法),形式如下: ```swift -.<#member name#> +.<#成员名称#> ``` 例如: @@ -1000,32 +584,13 @@ myFunction { [weak parent = self.parent] in print(parent!.title) } var x = MyEnumeration.someValue x = .anotherValue ``` - - - -如果推断类型是可选类型,则还可以在隐式成员表达式中使用非可选类型的成员。 +如果推断的是可选类型,可以在隐式成员表达式里使用不可选类型的成员。 ```swift var someOptional: MyEnumeration? = .someValue ``` - - -隐式成员表达式后面可以跟后缀运算符或中列出的其他后缀语法。这称为*链式隐式成员表达式*。尽管所有链接的后缀表达式都具有相同的类型是很常见的,但唯一的要求是整个链接的隐式成员表达式需要可转换为其上下文隐含的类型。具体来说,如果隐含类型是可选类型,则可以使用非可选类型的值,如果隐含类型是类类型,则可以使用其子类之一的值。例如: +隐式成员表达式可以跟在后缀运算符或者其他在里介绍的语法后面。这被称为 链式隐式成员表达式。尽管链式后缀表达式大多都是相同类型,但其实只需要整个链式成员表达式可以转换为上下文的类型就行了。更具体的,如果隐式类型是可选的,则可以使用非可选类型的值,如果隐式类型是类类型,则可以使用其子类的值。例如: ```swift class SomeClass { @@ -1042,112 +607,36 @@ let x: SomeClass = .shared.a.f() let y: SomeClass? = .shared let z: SomeClass = .sharedSubclass ``` +上面的代码中,`x` 的类型和上下文的隐式类型完全匹配,`y` 的类型是从 `SomeClass` 转换成 `SomeClass?`,`z` 的类型是从 `SomeSubclass` 转换成 `SomeClass`。 - - -在上面的代码中, `x` 的类型与其上下文隐含的类型完全匹配, `y` 的类型可以从 `SomeClass` 转换为 `SomeClass?` ,并且 `z` 的类型可以从 `SomeSubclass` 转换为 `SomeClass` 。 - -> 隐式成员表达式的语法: +> 隐式成员表达式语法 > > *implicit-member-expression* → **`.`** *identifier* \ > *implicit-member-expression* → **`.`** *identifier* **`.`** *postfix-expression* - +### 圆括号表达式 - - -### 带括号的表达式 - -带括号的表达式由括号包围的表达式组成。您可以使用括号通过显式分组表达式来指定运算的优先级。分组括号不会更改表达式的类型 --- 例如, `(1)` 的类型只是 `Int` - - - -> 括号表达式的语法 +> 圆括号表达式语法 > -> *parenthesized-expression* → **`(`** *expression* **`)`** +> *圆括号表达式* → **`(`** *表达式* **`)`** ### 元组表达式 -*元组表达式*由逗号分隔的表达式列表组成,并用括号括起来。每个表达式前面可以有一个可选标识符,用冒号 (`:`) 分隔。它具有以下形式: +*元组表达式*由圆括号和其中多个逗号分隔的子表达式组成。每个子表达式前面可以有一个标识符,用冒号隔开。元组表达式形式如下: ```swift -(<#identifier 1#>: <#expression 1#>, <#identifier 2#>: <#expression 2#>, <#...#>) +(<#标识符 1#>: <#表达式 1#>, <#标识符 2#>: <#表达式 2#>, <#...#>) ``` -元组表达式中的每个标识符在元组表达式的范围内必须是唯一的。在嵌套元组表达式中,同一嵌套级别的标识符必须是唯一的。例如, `(a: 10, a: 20)` 是无效的,因为标签 `a` 在同一级别出现了两次。然而, `(a: 10, b: (a: 1, x: 2))` 是有效的——虽然 `a`出现了两次,但它在外元组中出现一次,在内元组中出现一次。 +元组表达式里的每一个标识符在表达式作用域里必须是唯一的。在嵌套的元组表达式中,同嵌套层级里的标识符也必须是唯一的。例如,`(a: 10, a: 20)` 是不合法的,因为标签 `a` 在同一层级出现了两次。然而,`(a: 10, b: (a: 1, x: 2))` 是合法的,尽管 `a` 出现了两次,但有一次在外层元组里,一次在内层元组里。 - - -元组表达式可以包含零个表达式,也可以包含两个或多个表达式。括号内的单个表达式是括号表达式。 +> 注意:在 Swift 中,空的元组表达式和空的元组类型都写作 `()`。由于 `Void` 是 `()` 的类型别名,因此可以使用它来表示空的元组类型。虽然如此,`Void` 就像所有的类型别名一样,永远是一个类型——不能表示空的元组表达式。 -> 注意:Swift 中空元组表达式和空元组类型都写成 `()` 。因为 `Void` 是 `()` 的类型别名,所以您可以使用它来编写空元组类型。然而,像所有类型别名一样, `Void` 始终是一种类型——您不能使用它来编写空元组表达式。 - -> 元组表达式的语法: +> 元组表达式语法 > > *tuple-expression* → **`(`** **`)`** | **`(`** *tuple-element* **`,`** *tuple-element-list* **`)`** \ > *tuple-element-list* → *tuple-element* | *tuple-element* **`,`** *tuple-element-list* \ @@ -1155,32 +644,21 @@ let z: SomeClass = .sharedSubclass ### 通配符表达式 -*通配符表达式* 用于在赋值期间显式忽略某个值。例如,在以下赋值中,`10` 被分配给x ,20 被忽略: +*通配符表达式*可以在赋值过程中显式忽略某个值。例如下面的代码中,10 被赋值给 x,而 20 则被忽略: ```swift (x, _) = (10, 20) -// x is 10, and 20 is ignored +// x 为 10,20 被忽略 ``` - - - -> 通配符表达式的语法: +> 通配符表达式语法 > -> *wildcard-expression* → **`_`** +> *通配符表达式* → **`_`** -### 宏展开表达式 +### 宏表达式 -*宏扩展表达式* 由宏名称和后跟括号中的以逗号分隔的宏参数列表组成。宏在编译时展开。宏展开表达式具有以下形式: +Key-path 表达式引用一个类型的属性或下标。在动态语言中使场景可以使用 Key-path 表达式,例如观察键值对。格式为: ```swift <#macro name#>(<#macro argument 1#>, <#macro argument 2#>) @@ -1284,31 +762,6 @@ c.observe(\.someProperty) { object, change in } ``` - - - - 该*路径* 可以引用self来创建身份密钥路径 `( \.self )`。身份键路径引用整个实例,因此您可以使用它一步来访问和更改存储在变量中的所有数据。例如: ```swift @@ -1317,16 +770,6 @@ var compoundValue = (a: 1, b: 2) compoundValue[keyPath: \.self] = (a: 10, b: 20) ``` - - 该路径可以包含多个属性名称,以句点分隔,以引用属性值的属性。此代码使用关键路径表达式 `\OuterStructure.outer.someValue` 访问 `OuterStructure` 类型的 `outer` 属性的 `someValue` 属性: ```swift @@ -1344,26 +787,6 @@ let nestedValue = nested[keyPath: nestedKeyPath] // nestedValue is 24 ``` - - *路径*可以包含使用括号的下标,只要下标的参数类型符合 `Hashable` 协议即可。此示例使用键路径中的下标来访问数组的第二个元素: ```swift @@ -1371,25 +794,6 @@ let greetings = ["hello", "hola", "bonjour", "안녕"] let myGreeting = greetings[keyPath: \[String].[1]] // myGreeting is 'hola' ``` - - - - - 下标中使用的值可以是命名值或文字。使用值语义在关键路径中捕获值。以下代码在键路径表达式和闭包中使用变量 `index` 来访问 `greetings` 数组的第三个元素。当 `index` 被修改时,键路径表达式仍然引用第三个元素,而闭包使用新索引。 ```swift @@ -1411,31 +815,6 @@ print(greetings[keyPath: path]) print(fn(greetings)) // Prints "안녕" ``` - - - 该路径可以使用可选链接和强制展开。此代码在键路径中使用可选链接来访问可选字符串的属性: ```swift @@ -1448,27 +827,6 @@ let count = greetings[keyPath: \[String].first?.count] print(count as Any) // Prints "Optional(5)" ``` - - - - - 您可以混合和匹配关键路径的组件来访问深度嵌套在类型中的值。以下代码通过使用组合这些组件的键路径表达式来访问数组字典的不同值和属性。 ```swift @@ -1484,25 +842,6 @@ print(interestingNumbers[keyPath: \[String: [Int]].["hexagonal"]!.count]) print(interestingNumbers[keyPath: \[String: [Int]].["hexagonal"]!.count.bitWidth]) // Prints "64" ``` - - - 您可以在通常提供函数或闭包的上下文中使用键路径表达式。具体来说,您可以使用根类型为 `SomeType` 且其路径生成 `Value` 类型的值的键路径表达式,而不是 `(SomeType) -> Value` 类型的函数或闭包。 ```swift @@ -1520,34 +859,6 @@ var toDoList = [ let descriptions = toDoList.filter(\.completed).map(\.description) let descriptions2 = toDoList.filter { $0.completed }.map { $0.description } ``` - - - - - 关键路径表达式的任何副作用仅在计算表达式的点进行计算。例如,如果您在关键路径表达式的下标内进行函数调用,则该函数仅在计算表达式时调用一次,而不是每次使用关键路径时都被调用。 ```swift @@ -1563,25 +874,6 @@ let taskKeyPath = \[Task][makeIndex()] let someTask = toDoList[keyPath: taskKeyPath] ``` - - 有关在与 Objective-C API 交互的代码中使用关键路径的更多信息,请参阅 [Using Objective-C Runtime Features in Swift](https://developer.apple.com/documentation/swift/using_objective_c_runtime_features_in_swift). 有关键值编码和键值观察的信息,请参阅[Key-Value Coding Programming Guide](https://developer.apple.com/library/content/documentation/Cocoa/Conceptual/KeyValueCoding/index.html#//apple_ref/doc/uid/10000107i) 和 [Key-Value Observing Programming Guide](https://developer.apple.com/library/content/documentation/Cocoa/Conceptual/KeyValueObserving/KeyValueObserving.html#//apple_ref/doc/uid/10000177i). @@ -1879,43 +1171,17 @@ myData.someMethod() { $0 == 13 } myData.someMethod { $0 == 13 } ``` - - - - 为了在参数中包含尾随闭包,编译器从左到右检查函数的参数,如下所示: -| 尾随闭包 | 范围 | 行动 | +| 尾随闭包 | 形参 | 行动 | | ---------------- | --------- | ------ | -| 贴上标签 | 贴上标签 | 如果标签相同,则闭包与参数匹配;否则,该参数将被跳过。| -| 贴上标签 | 未标记 | 该参数被跳过。 | -| 未标记 | 有标签或无标签 | 如果参数在结构上类似于函数类型(如下定义),则闭包与参数匹配;否则,该参数将被跳过。 | +| 有标签 | 有标签 | 如果标签相同,闭包和形参匹配,否则跳过该形参| +| 有标签 | 无标记 | 跳过该形参 | +| 无标签 | 有标签或无标签 | 如果形参在结构上类似于下面定义的函数类型,和闭包匹配,否则跳过该形参 | -尾随闭包作为其匹配参数的参数传递。在扫描过程中跳过的参数没有传递给它们的参数——例如,它们可以使用默认参数。找到匹配项后,将继续扫描下一个尾随闭包和下一个参数。在匹配过程结束时,所有尾随闭包都必须有匹配项。 +尾随闭包作为其匹配形参的实参传递。在扫描过程被跳过的形参不传递实参——例如,它们使用的是默认形参。当匹配后,扫描会继续下一个尾随闭包和形参。匹配过程结束后,所有的尾随闭包必须有对应的匹配。 -如果参数不是输入输出参数,并且参数是以下之一,则该参数在结构上类似于函数类型: +如果形参不是输入输出参数,并且类似下面的情况,则算是结构上类似函数类型: - 类型为函数类型的参数,如`(Bool) -> Int` - 一个自动闭包参数,其包装表达式的类型是函数类型,例如 `@autoclosure () -> ((Bool) -> Int)` @@ -1923,34 +1189,10 @@ myData.someMethod { $0 == 13 } - 其类型被包裹在一层或多层可选中的参数,例如`Optional<(Bool) -> Int>` - 其类型组合了这些允许类型的参数,例如 `(Optional<(Bool) -> Int>)...` -当尾随闭包与结构上类似于函数类型但不是函数的参数匹配时,闭包将根据需要进行包装。例如,如果参数的类型是可选类型,则闭包会自动包装在 `Optional` 中. - - -为了简化从 5.3 之前的 Swift 版本(执行从右到左的匹配)的代码迁移,编译器会检查从左到右和从右到左的顺序。如果扫描方向产生不同的结果,则使用旧的从右到左排序,并且编译器会生成警告。 Swift 的未来版本将始终使用从左到右的排序。 +为了简化 Swift 5.3 之前版本(从右到左匹配)的代码迁移 —— 编译器会同时检查从左到右和从右到左的顺序。如果不同的扫描方向产生了不同的结果,编译器则使用旧的从右到左的顺序,并生成警告。Swift 的未来版本将都使用从左到右的顺序。 ```swift typealias Callback = (Int) -> Int @@ -1961,51 +1203,18 @@ func someFunction(firstClosure: Callback? = nil, print(first ?? "-", second ?? "-") } -someFunction() // Prints "- -" -someFunction { return $0 + 100 } // Ambiguous -someFunction { return $0 } secondClosure: { return $0 } // Prints "10 20" +someFunction() // 打印 "- -" +someFunction { return $0 + 100 } // 歧义 +someFunction { return $0 } secondClosure: { return $0 } // 打印 "10 20" ``` - - -在上面的示例中,标记为“Ambigitude”的函数调用会打印“- 120”,并在 Swift 5.3 上生成编译器警告。 Swift 的未来版本将打印“110 -”。 - - +在上面的例子中,Swift 5.3 中被标记为“歧义”的函数调用会打印”- 120“并产生一个编辑器警告。未来版本的 Swift 会打印”110 -“。 -类、结构或枚举类型可以通过声明多种方法之一来启用函数调用语法的语法糖,如 中所述。 +如 所述,通过声明几种方法中的一种,类、结构体或枚举类型可以为函数调用语法启用语法糖。 -#### 隐式转换为指针类型 +#### 指针类型的隐式转换 -在函数调用表达式中,如果参数和参数具有不同的类型,编译器会尝试通过应用以下列表中的隐式转换之一来使它们的类型匹配: +在函数调用表达式里,如果实参和形参的类型不一致,编译器会尝试通过下面的规则进行隐式转换来匹配类型: - `inout SomeType` 可以成为 `UnsafePointer` 或 `UnsafeMutablePointer` @@ -2014,7 +1223,7 @@ someFunction { return $0 } secondClosure: { return $0 } // Prints "10 20" - `Array`可以成为`UnsafePointer` - `String`可以成为`UnsafePointer` -以下两个函数调用是等效的: +下面两个函数调用是等价的: ```swift func unsafeFunction(pointer: UnsafePointer) { @@ -2026,72 +1235,12 @@ unsafeFunction(pointer: &myNumber) withUnsafePointer(to: myNumber) { unsafeFunction(pointer: $0) } ``` - - -通过这些隐式转换创建的指针仅在函数调用期间有效。为了避免未定义的行为,请确保您的代码在函数调用结束后永远不会保留指针。 +隐式转换创建的指针仅在函数调用期间有效。为了避免发生未定义行为,确保代码在函数调用结束后没有继续持有这些指针。 -> 当将数组隐式转换为不安全指针时,Swift 通过根据需要转换或复制数组来确保数组的存储是连续的。例如,您可以将此语法与从 `NSArray` 子类桥接到 `Array` 的数组一起使用,该子类不对其存储制定任何 API 约定。如果您需要保证数组的存储已经是连续的,因此隐式转换永远不需要执行此工作,请使用 `ContiguousArray` 而不是 `Array` 。 +> 注意 +> 当将数组隐式转换为不安全指针时,Swift 会按需转换或复制数组来确保数组的存储是连续的。例如,可以用此语法将没有> 约定存储 API 的 `NSArray` 子类桥接到 `Array` 的数组。如果能确保数组的存储是连续的,就不需要隐式转换来做这个工> 作,这种情况下可以用 `ContiguousArray` 代替 `Array`。 -使用`&`而不是像`withUnsafePointer(to:)`这样的显式函数可以帮助提高对低级 C 函数的调用的可读性,特别是当函数采用多个指针参数时。但是,当从其他 Swift 代码调用函数时,请避免使用`&`而应显式使用不安全的 API。 - - +使用 `&` 代替类似 `withUnsafePointer(to:)` 的显式函数可以在调用底层 C 函数的可读性更高,特别是当函数传入多个指针实参时。如果是其他 Swift 代码调用函数,避免使用 `&` 代替显式的不安全 API。 > 函数调用表达式的语法: > @@ -2107,151 +1256,78 @@ withUnsafePointer(to: myNumber) { unsafeFunction(pointer: $0) } > *labeled-trailing-closures* → *labeled-trailing-closure* *labeled-trailing-closures*_?_ \ > *labeled-trailing-closure* → *identifier* **`:`** *closure-expression* -### 初始化表达式 +### 构造器表达式 -初始值设定项表达式提供对类型的初始值设定项的访问。它具有以下形式: +构造器表达式用于访问某个类型的构造器,形式如下: ```swift -<#expression#>.init(<#initializer arguments#>) +<#表达式#>.init(<#构造函数#>) ``` -您可以在函数调用表达式中使用初始化表达式来初始化类型的新实例。您还可以使用初始值设定项表达式来委托给超类的初始值设定项。 +你可以在函数调用表达式中使用构造器表达式来初始化某个类型的新实例。也可以使用构造器表达式来代理给父类构造器。 ```swift class SomeSubClass: SomeSuperClass { override init() { - // subclass initialization goes here + // 此处为子类构造过程 super.init() } } ``` - - -与函数一样,初始化器可以用作值。例如: +和函数类似,构造器表达式可以作为一个值。 例如: ```swift -// Type annotation is required because String has multiple initializers. +// 类型注解是必须的,因为 String 类型有多种构造器 let initializer: (Int) -> String = String.init let oneTwoThree = [1, 2, 3].map(initializer).reduce("", +) print(oneTwoThree) -// Prints "123" +// 打印 "123" ``` - - - -如果按名称指定类型,则可以访问该类型的初始值设定项,而无需使用初始值设定项表达式。在所有其他情况下,您必须使用初始化表达式。 +如果通过名字来指定某个类型,可以不用构造器表达式而直接使用类型的构造器。在其他情况下,你必须使用构造器表达式。 ```swift -let s1 = SomeType.init(data: 3) // Valid -let s2 = SomeType(data: 1) // Also valid +let s1 = SomeType.init(data: 3) // 有效 +let s2 = SomeType(data: 1) // 有效 -let s3 = type(of: someValue).init(data: 7) // Valid -let s4 = type(of: someValue)(data: 5) // Error +let s3 = type(of: someValue).init(data: 7) // 有效 +let s4 = type(of: someValue)(data: 5) // 错误 ``` - - -> 初始化表达式的语法: +> 构造器表达式语法: > -> *initializer-expression* → *postfix-expression* **`.`** **`init`** \ -> *initializer-expression* → *postfix-expression* **`.`** **`init`** **`(`** *argument-names* **`)`** +> *构造器表达式语法* → *后缀表达式* **`.`** **`init`** \ +> *构造器表达式 * → *后缀表达式* **`.`** **`init`** **`(`** *参数名称* **`)`** ### 显式成员表达式 -*显式成员表达式*允许访问命名类型、元组或模块的成员。它由项目与其成员标识符之间的句点 ( `.` ) 组成。 +*显式成员表达式*允许我们访问命名类型、元组或者模块的成员,其形式如下: ```swift -<#expression#>.<#member name#> +<#表达名#>.<#成员名#> ``` -命名类型的成员被命名为类型声明或扩展的一部分。例如: +命名类型的某个成员在原始实现或者扩展中定义,例如: ```swift class SomeClass { var someProperty = 42 } let c = SomeClass() -let y = c.someProperty // Member access +let y = c.someProperty // 访问成员 ``` - - - 元组的成员按照它们出现的顺序使用整数隐式命名,从零开始。例如: ```swift var t = (10, 20, 30) t.0 = t.1 -// Now t is (20, 20, 30) +// 现在元组 t 为 (20, 20, 30) ``` +对于模块的成员来说,只能直接访问顶级声明中的成员。 - - -模块的成员访问该模块的顶级声明。 +使用 `dynamicMemberLookup` 属性声明的类型包含可以在运行时查找的成员,具体请参阅 。 -使用`dynamicMemberLookup`属性声明的类型包括在运行时查找的成员,如 中所述。 - -为了区分名称仅因参数名称而不同的方法或初始化器, - -要区分名称仅因参数名称不同的方法或初始值设定项,请将参数名称包含在括号中,每个参数名称后跟一个冒号 `:` )。为没有名称的参数写入下划线 ( `_` )。要区分重载方法,请使用类型注释。例如: +为了区分只有参数名有所不同的方法或构造器,在圆括号中写出参数名,参数名后紧跟一个冒号,对于没有参数名的参数,使用下划线代替参数名。而对于重载方法,则需使用类型注解进行区分。例如: ```swift class SomeClass { @@ -2262,63 +1338,15 @@ class SomeClass { } let instance = SomeClass() -let a = instance.someMethod // Ambiguous -let b = instance.someMethod(x:y:) // Unambiguous +let a = instance.someMethod // 有歧义 +let b = instance.someMethod(x:y:) // 无歧义 -let d = instance.overloadedMethod // Ambiguous +let d = instance.overloadedMethod // 有歧义 let d = instance.overloadedMethod(x:y:) // Still ambiguous let d: (Int, Bool) -> Void = instance.overloadedMethod(x:y:) // Unambiguous ``` - - -如果句点出现在行的开头,则它将被理解为显式成员表达式的一部分,而不是隐式成员表达式。例如,以下清单显示了分为几行的链式方法调用: +如果点号(`.`)出现在行首,它会被视为显式成员表达式的一部分,而不是隐式成员表达式的一部分。例如如下代码所展示的被分为多行的链式方法调用: ```swift let x = [10, 3, 20, 15, 4] @@ -2326,21 +1354,7 @@ let x = [10, 3, 20, 15, 4] .filter { $0 > 5 } .map { $0 * 100 } ``` - - - -您可以将此多行链式语法与编译器控制语句结合起来,以控制每个方法的调用时间。例如,以下代码在 iOS 上使用不同的过滤规则: +你可以将这种多行链式语法与编译器控制语句结合,以控制调用每个方法的时间。例如,以下代码在 iOS 上应用了不同的过滤规则:: ```swift let numbers = [10, 20, 33, 43, 50] @@ -2350,73 +1364,13 @@ let numbers = [10, 20, 33, 43, 50] .filter { $0 > 25 } #endif ``` +在 `#if`、`#endif` 和其它编译指令之间的条件编译块可以包含一个隐式成员表达式,后跟零个或多个后缀,以形成一个后缀表达式。这些条件编译块还可以包含另一个条件编译块,或者这些表达式和块的组合体。 - - -在 `#if` 、 `#endif`和其他编译指令之间,条件编译块可以包含隐式成员表达式,后跟零个或多个后缀,以形成后缀表达式。它还可以包含另一个条件编译块,或这些表达式和块的组合。 - -您可以在任何可以编写显式成员表达式的地方使用此语法,而不仅仅是在顶级代码中。 - -在条件编译块中, `#if` 编译指令的分支必须至少包含一个表达式。其他分支可以为空。 - - - - - - +在条件编译块中,编译指令 `#if` 的分支必须包含至少一个表达式,其它分支可以为空。 -> 显式成员表达式的语法: +> 显式成员表达式语法: > > *explicit-member-expression* → *postfix-expression* **`.`** *decimal-digits* \ > *explicit-member-expression* → *postfix-expression* **`.`** *identifier* *generic-argument-clause*_?_ \ @@ -2426,153 +1380,84 @@ let numbers = [10, 20, 33, 43, 50] > *argument-names* → *argument-name* *argument-names*_?_ \ > *argument-name* → *identifier* **`:`** - - - - -### 自我表达 +### 后缀 self 表达式 -后缀`self` 表达式由表达式或类型名称组成,后跟 `.self` 。它有以下几种形式: +后缀`self` 表达式由某个表达式或类型名紧跟 `.self` 组成,其形式如下: ```swift -<#expression#>.self -<#type#>.self +<#表达式#>.self +<#类型#>.self ``` -第一种形式计算表达式的值。例如, `x.self` 计算结果为 `x` 。 +第一种形式返回表达式的值。例如:`x.self` 返回 `x`。 -第二种形式求值为*type*的值。使用此形式将类型作为值进行访问。例如,由于 `SomeClass.self` 计算结果为 `SomeClass` 类型本身,因此您可以将其传递给接受类型级参数的函数或方法。 +第二种形式返回相应的类型。我们可以用它来获取某个实例的类型作为一个值来使用。例如,`SomeClass.self` 会返回 `SomeClass` 类型本身,你可以将其传递给相应函数或者方法作为参数。 -> 后缀自我表达的语法: +> 后缀 self 表达式语法 > -> *postfix-self-expression* → *postfix-expression* **`.`** **`self`** +> *后缀 self 表达式* → * 后缀表达式* **`.`** **`self`** ### 下标表达式 -*下标表达式*使用相应下标声明的 getter 和 setter 提供下标访问。它具有以下形式: +可通过下标表达式访问相应的下标,形式如下: ```swift -<#expression#>[<#index expressions#>] +<#表达式#>[<#索引表达式#>] ``` -为了计算下标表达式的值,需要调用表达式类型的下标 getter,并将索引表达式作为下标参数传递。为了设置它的值,以同样的方式调用下标设置器。 +要获取下标表达式的值,可将索引表达式作为下标表达式的参数来调用下标 getter。下标 setter 的调用方式与之一样。 - 有关下标声明的信息,请参阅 . -> 下标表达式的语法: +> 下标表达式语法: > > *subscript-expression* → *postfix-expression* **`[`** *function-call-argument-list* **`]`** - - -### 强制值表达 +### 强制取值表达式 -*强制值表达式*会解包您确定不是 `nil` 的可选值。它具有以下形式: +当你确定可选值不是 `nil` 时,可以使用强制取值表达式来强制解包,形式如下: ```swift -<#expression#>! +<#表达式#>! ``` -如果表达式的值不是 `nil` ,则可选值将被解包并以相应的非可选类型返回。否则,会引发运行时错误。 +如果该表达式的值不是 `nil`,则返回解包后的值。否则,抛出运行时错误。 -可以通过改变值本身或分配给值的成员之一来修改强制值表达式的展开值。例如: +返回的值可以被修改,无论是修改值本身,还是修改值的成员。例如: ```swift var x: Int? = 0 x! += 1 -// x is now 1 +// x 现在是 1 var someDictionary = ["a": [1, 2, 3], "b": [10, 20]] someDictionary["a"]![0] = 100 -// someDictionary is now ["a": [100, 2, 3], "b": [10, 20]] +// someDictionary 现在是 ["a": [100, 2, 3], "b": [10, 20]] ``` - - - -> 强制值表达式的语法: +> 强制取值语法 > > *强制值表达式* → *后缀表达式* **`!`** ### 可选链式表达式 -*可选链表达式*提供了在后缀表达式中使用可选值的简化语法。它具有以下形式: +*可选链表达式*提供了一种使用可选值的便捷方法,形式如下: ```swift -<#expression#>? +<#表达式#>? ``` -后缀 `?` 运算符从表达式创建可选链表达式而不更改表达式的值。 +后缀 `?` 运算符会根据表达式生成可选链表达式而不会改变表达式的值。 -可选链表达式必须出现在后缀表达式中,并且它们会导致后缀表达式以特殊方式进行计算。如果可选链表达式的值为 `nil` ,则后缀表达式中的所有其他操作都将被忽略,并且整个后缀表达式的计算结果为 `nil` 。如果可选链表达式的值不是 `nil` ,则可选链表达式的值将被展开并用于计算后缀表达式的其余部分。无论哪种情况,后缀表达式的值仍然是可选类型。 +如果某个后缀表达式包含可选链表达式,那么它的执行过程会比较特殊。如果该可选链表达式的值是 `nil`,整个后缀表达式会直接返回 `nil`。如果该可选链表达式的值不是 `nil`,则返回可选链表达式解包后的值,并将该值用于后缀表达式中剩余的表达式。在这两种情况下,整个后缀表达式的值都会是可选类型。 -如果包含可选链表达式的后缀表达式嵌套在其他后缀表达式中,则只有最外面的表达式返回可选类型。在下面的示例中,当 `c `不为 `nil`时,其值将被展开并用于计算 `.property` ,其值用于计算 `.performAction()` 。整个表达式 `c?.property.performAction()`具有可选类型的值。 +如果某个后缀表达式中包含了可选链表达式,那么只有最外层的表达式会返回一个可选类型。例如,在下面的例子中,如果 `c` 不是 `nil`,那么它的值会被解包,然后通过 `.property` 访问它的属性,接着进一步通过 `.performAction()` 调用相应方法。整个 `c?.property.performAction()` 表达式返回一个可选类型的值,而不是多重可选类型。 ```swift var c: SomeClass? var result: Bool? = c?.property.performAction() ``` - - - -以下示例显示了上面示例的行为,而不使用可选链。 +上面的例子跟下面的不使用可选链表达式的例子等价: ```swift var result: Bool? @@ -2580,22 +1465,7 @@ if let unwrappedC = c { result = unwrappedC.property.performAction() } ``` - - - -可以通过改变值本身或分配给值的成员之一来修改可选链表达式的展开值。如果可选链表达式的值为nil ,则不计算赋值运算符右侧的表达式。例如: +可选链表达式解包后的值可以被修改,无论是修改值本身,还是修改值的成员。如果可选链表达式的值为 `nil`,则表达式右侧的赋值操作不会被执行。例如: ```swift func someFunctionWithSideEffects() -> Int { @@ -2611,32 +1481,9 @@ someDictionary["a"]?[0] = someFunctionWithSideEffects() // someFunctionWithSideEffects is evaluated and returns 42 // someDictionary is now ["a": [42, 2, 3], "b": [10, 20]] ``` - - - > 可选链表达式的语法: > -> *optional-chaining-expression* → *postfix-expression* **`?`** +> *可选链表达式* → *后缀表达式* **`?`** > 测试版软件: > From 81403997a2e688c78983bfe7b9d5d0a8b75d2f9b Mon Sep 17 00:00:00 2001 From: King <66349714+king-open@users.noreply.github.com> Date: Sun, 20 Oct 2024 18:15:14 +0800 Subject: [PATCH 11/14] =?UTF-8?q?docs:=20=E9=87=8D=E6=96=B0=E7=BF=BB?= =?UTF-8?q?=E8=AF=91=E4=BA=86=E8=BF=99=E7=AF=87=E6=96=87=E7=AB=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- swift-6-beta.docc/ReferenceManual/Patterns.md | 2677 +---------------- 1 file changed, 131 insertions(+), 2546 deletions(-) diff --git a/swift-6-beta.docc/ReferenceManual/Patterns.md b/swift-6-beta.docc/ReferenceManual/Patterns.md index 5333fbdff..2e02e55aa 100644 --- a/swift-6-beta.docc/ReferenceManual/Patterns.md +++ b/swift-6-beta.docc/ReferenceManual/Patterns.md @@ -1,2646 +1,231 @@ -# 表达式 +# 模式 -访问、修改和分配值。 +模式代表单个值或者复合值的结构。例如,元组 `(1, 2)` 的结构是由逗号分隔的,包含两个元素的列表。因为模式代表一种值的结构,而不是特定的某个值,你可以利用模式来匹配各种各样的值。比如,`(x, y)` 可以匹配元组 `(1, 2)`,以及任何含两个元素的元组。除了利用模式匹配一个值以外,你可以从复合值中提取出部分或全部值,然后分别把各个部分的值和一个常量或变量绑定起来。 -在 Swift 中,有四种表达式:前缀表达式、中缀表达式、主表达式和后缀表达式。计算表达式会返回一个值、导致副作用,或两者兼而有之。 +Swift 中的模式分为两类:一种能成功匹配任何类型的值,另一种在运行时匹配某个特定值时可能会失败。 -前缀和中缀表达式允许您将运算符应用于较小的表达式。主表达式在概念上是最简单的表达式,它们提供了一种访问值的方法。后缀表达式与前缀和中缀表达式一样,允许您使用后缀构建更复杂的表达式,例如函数调用和成员访问。下面各节详细描述了每种表达式。 +第一类模式用于解构简单变量、常量和可选绑定中的值。此类模式包括通配符模式、标识符模式,以及包含前两种模式的值绑定模式和元组模式。你可以为这类模式指定一个类型注解,从而限制它们只能匹配某种特定类型的值。 -> 表达式的语法: -> -> *expression* → *try-operator*_?_ *await-operator*_?_ *prefix-expression* *infix-expressions*_?_ \ - -## 前缀表达式 - -前缀表达式将可选的前缀运算符与表达式结合起来。前缀运算符采用一个参数,即它们后面的表达式。 - -有关这些运算符的行为的信息,请参阅。 - -有关 Swift 标准库提供的运算符的信息,请参阅[Operator Declarations](https://developer.apple.com/documentation/swift/operator_declarations)。 - -> 前缀表达式的语法: -> -> *prefix-expression* → *prefix-operator*_?_ *postfix-expression* \ -> *prefix-expression* → *in-out-expression* - -### 输入输出表达式 - -输入输出表达式标记作为输入输出参数传递给函数调用表达式的变量。 - -```swift -&<#expression#> -``` - -有关输入输出参数的更多信息以及查看示例,请参阅. - -在需要指针的上下文中提供非指针参数时,也会使用输入输出表达式,如 中所述。 - -> 输入输出表达式的语法: -> -> *in-out-expression* → **`&`** *primary-expression* - -### 尝试操作员 - - try 表达式由`try` 运算符后跟一个可能引发错误的表达式组成。它具有以下形式: - -```swift -try <#expression#> -``` -`try` 表达式的值是 *表达式*的值. - -可选的 try 表达式由`try?` 组成。运算符后跟可能引发错误的表达式。它具有以下形式: - - -```swift -try? <#expression#> -``` - -如果表达式没有抛出错误,则可选尝试表达式的值是包含表达式值的可选值。否则,可选尝试表达式的值为 `nil`。 - -强制尝试表达式由`try!` 组成。运算符后跟可能引发错误的表达式。它具有以下形式: - - - -```swift -try! <#expression#> -``` - -强制尝试表达式的值是表达式的值。如果表达式抛出错误,则会产生运行时错误。 - -当中缀运算符左侧的表达式标有 `try` 时, `try?` ,或者 `try!` ,该运算符适用于整个中缀表达式。也就是说,您可以使用括号来明确运算符应用程序的范围。 - -```swift -// try applies to both function calls -sum = try someThrowingFunction() + anotherThrowingFunction() - -// try applies to both function calls -sum = try (someThrowingFunction() + anotherThrowingFunction()) - -// Error: try applies only to the first function call -sum = (try someThrowingFunction()) + anotherThrowingFunction() -``` - - - -`try` 表达式不能出现在中缀运算符的右侧,除非中缀运算符是赋值运算符或者 `try`表达式括在括号中。 - - - - -如果表达式同时包含`try`和`await`运算符,则`try`运算符必须首先出现。 - - - - -有关更多信息并查看如何使用`try`、`try?`的示例,并 `try! ` 请参阅 . - -> try 表达式的语法: -> -> *try-operator* → **`try`** | **`try`** **`?`** | **`try`** **`!`** - -### 等待接线员 - -*wait* 表达式由`await`运算符后跟一个使用异步操作结果的表达式组成。它具有以下形式 - -```swift -await <#expression#> -``` -`await`表达式的值是expression的值。标有await表达式称为 *潜在挂起点* 。异步函数的执行可以在每个用 `await`标记的表达式处暂停。此外,并发代码的执行永远不会在任何其他点暂停。这意味着潜在挂起点之间的代码可以安全地更新需要暂时破坏不变量的状态,前提是它在下一个潜在挂起点之前完成更新。 - - - -`await` 表达式只能出现在异步上下文中,例如传递给 `async(priority:operation:)`函数的尾随闭包。它不能出现在defer语句的主体中,也不能出现在同步函数类型的自动闭包中。 - -当中缀运算符左侧的表达式用`await`运算符标记时,该运算符适用于整个中缀表达式。也就是说,您可以使用括号来明确运算符应用程序的范围。 - -```swift -// await applies to both function calls -sum = await someAsyncFunction() + anotherAsyncFunction() - -// await applies to both function calls -sum = await (someAsyncFunction() + anotherAsyncFunction()) - -// Error: await applies only to the first function call -sum = (await someAsyncFunction()) + anotherAsyncFunction() -``` - - - -`await`表达式不能出现在中缀运算符的右侧,除非中缀运算符是赋值运算符或者将await表达式括在括号中。 - - - -如果表达式同时包含 `await`和try运算符,则try运算符必须首先出现。 - - - -> 等待表达的语法: -> -> *等待运算符* → **`await`** - -## 中缀表达式 - -*中缀表达式* 将中缀二元运算符与其作为其左侧和右侧参数的表达式组合起来。它具有以下形式: - -```swift -<#left-hand argument#> <#operator#> <#right-hand argument#> -``` - -有关这些运算符的行为的信息,请参阅 . - -有关 Swift 标准库提供的运算符的信息,请参阅 [Operator Declarations](https://developer.apple.com/documentation/swift/operator_declarations). - - - -> 注意:在解析时,由中缀运算符组成的表达式表示为平面列表。通过应用运算符优先级将该列表转换为树。例如,表达式2 + 3 * 5最初被理解为五个项目2 、 + 、 3 、 *和5的平面列表。此过程将其转换为树 (2 + (3 * 5))。 - -> 中缀表达式的语法: -> -> *infix-expression* → *infix-operator* *prefix-expression* \ -> *infix-expression* → *assignment-operator* *try-operator*_?_ *await-operator*_?_ *prefix-expression* \ -> *infix-expression* → *conditional-operator* *try-operator*_?_ *await-operator*_?_ *prefix-expression* \ -> *infix-expression* → *type-casting-operator* \ -> *infix-expressions* → *infix-expression* *infix-expressions*_?_ - -### 赋值运算符 - -*赋值运算符* 为给定表达式设置新值。它具有以下形式: - -```swift -<#expression#> = <#value#> -``` - -*表达式* 的值设置为通过计算*value* 获得的值。如果表达式是元组,则值必须是具有相同元素数量的元组。 (允许嵌套元组。)从值的每个部分到表达式的相应部分执行赋值。例如: - -```swift -(a, _, (b, c)) = ("test", 9.45, (12, 3)) -// a is "test", b is 12, c is 3, and 9.45 is ignored -``` - - - -赋值运算符不返回任何值。 - -> 赋值运算符的语法: -> -> *赋值运算符* → **`=`** - -### 三元条件运算符 - -*三元条件运算符*根据条件值计算两个给定值之一。它具有以下形式: - -```swift -<#condition#> ? <#expression used if true#> : <#expression used if false#> -``` - -如果*条件*计算结果为`true` ,则条件运算符计算第一个表达式并返回其值。否则,它计算第二个表达式并返回其值。不计算未使用的表达式。 - -有关使用三元条件运算符的示例,请参阅文档: . - -> 条件运算符的语法: -> -> *条件运算符* → **`?`** *表达* **`:`** - -### 类型转换运算符 - -有四种类型转换运算符: `is`运算符、`as`运算符、`as?`运算符和`as!`操作员。 - -它们具有以下形式: - -```swift -<#expression#> is <#type#> -<#expression#> as <#type#> -<#expression#> as? <#type#> -<#expression#> as! <#type#> -``` - -`is`运算符在运行时检查表达式是否可以转换为指定类型。如果*表达式*可以转换为指定*类型*,则返回`true` ;否则,返回`false` 。 - - - - - -当在编译时已知转换始终成功时,`as`运算符会执行转换,例如向上转换或桥接。向上转换允许您使用表达式作为其类型的超类型的实例,而无需使用中间变量。以下方法是等效的: - -```swift -func f(_ any: Any) { print("Function for Any") } -func f(_ int: Int) { print("Function for Int") } -let x = 10 -f(x) -// Prints "Function for Int" - -let y: Any = x -f(y) -// Prints "Function for Any" - -f(x as Any) -// Prints "Function for Any" -``` - - - -桥接允许您使用`Swift` 标准库类型(例如String的表达式作为其相应的基础类型(例如NSString ,而无需创建新实例。有关桥接的更多信息,请参阅[Working with Foundation Types](https://developer.apple.com/documentation/swift/imported_c_and_objective_c_apis/working_with_foundation_types). - -`as?`运算符执行表达式到指定类型的条件转换。 `as?`运算符返回指定类型的可选值。在运行时,如果转换成功,则将表达式的值包装在可选值中并返回;否则,返回值为`nil` 。如果强制转换为指定类型肯定会失败或一定会成功,则会引发编译时错误。 - -`as!`运算符将表达式强制转换为指定类型。 `as!`运算符返回指定类型的值,而不是可选类型。如果转换失败,则会引发运行时错误。 `x as! T`与 `(x as? T)!` 。 - -有关类型转换的更多信息以及查看使用类型转换运算符的示例,请参阅. - -> 类型转换运算符的语法: -> -> *类型转换运算符* → **`is`** *类型* \ -> *类型转换运算符* → **`as`** *类型* \ -> *类型转换运算符* → **`as`** **`?`** *类型* \ -> *类型转换运算符* → **`as`** **`!`** *类型* - -## 主要表达 - -*初级表达式*是最基本的表达式。它们可以单独用作表达式,也可以与其他标记组合以构成前缀表达式、中缀表达式和后缀表达式。 - -> 基本表达式的语法: -> -> *primary-expression* → *identifier* *generic-argument-clause*_?_ \ -> *primary-expression* → *literal-expression* \ -> *primary-expression* → *self-expression* \ -> *primary-expression* → *superclass-expression* \ -> *primary-expression* → *conditional-expression* \ -> *primary-expression* → *closure-expression* \ -> *primary-expression* → *parenthesized-expression* \ -> *primary-expression* → *tuple-expression* \ -> *primary-expression* → *implicit-member-expression* \ -> *primary-expression* → *wildcard-expression* \ -> *primary-expression* → *macro-expansion-expression* \ -> *primary-expression* → *key-path-expression* \ -> *primary-expression* → *selector-expression* \ -> *primary-expression* → *key-path-string-expression* - - - - - -### 文字表达 - -文字表达式由普通文字(例如字符串或数字)、数组或字典文字或游乐场文字组成 - -> Note: -> Prior to Swift 5.9, -> the following special literals were recognized: -> `#column`, -> `#dsohandle`, -> `#fileID`, -> `#filePath`, -> `#file`, -> `#function`, -> and `#line`. -> These are now implemented as macros in the Swift standard library: -> [`column()`](https://developer.apple.com/documentation/swift/column()), -> [`dsohandle()`](https://developer.apple.com/documentation/swift/dsohandle()), -> [`fileID()`](https://developer.apple.com/documentation/swift/fileID()), -> [`filePath()`](https://developer.apple.com/documentation/swift/filePath()), -> [`file()`](https://developer.apple.com/documentation/swift/file()), -> [`function()`](https://developer.apple.com/documentation/swift/function()), -> and [`line()`](https://developer.apple.com/documentation/swift/line()). - - - -*数组文字*是值的有序集合。它具有以下形式: - -```swift -[<#value 1#>, <#value 2#>, <#...#>] -``` - -数组中的最后一个表达式后面可以跟一个可选的逗号。数组文字的值具有类型`[T]` ,其中T是其中表达式的类型。如果存在多种类型的表达式,则`T` 是它们最接近的公共超类型。空数组文字使用一对空方括号编写,可用于创建指定类型的空数组。 - -```swift -var emptyArray: [Double] = [] -``` - - - -*字典文字* 是键值对的无序集合。它具有以下形式: - -```swift -[<#key 1#>: <#value 1#>, <#key 2#>: <#value 2#>, <#...#>] -``` - -字典中的最后一个表达式后面可以跟一个可选的逗号。字典文字的值具有类型`[Key: Value]` ,其中 `Key`是其键表达式的类型, `Value` 是其值表达式的类型。如果存在多种类型的表达式,则`Key`和`Value`是其各自值最接近的公共超类型。空字典文字被写为一对括号 `( [:] )` 内的冒号,以将其与空数组文字区分开。您可以使用空字典文字来创建指定键和值类型的空字典文字。 - -```swift -var emptyDictionary: [String: Double] = [:] -``` - - - -Xcode 使用 *Playground* 文字在程序编辑器中创建颜色、文件或图像的交互式表示。 Xcode 之外的纯文本 Playground 文字使用特殊的文字语法表示。 - -有关在 Xcode 中使用 Playground 文字的信息,请参阅 Xcode 帮助中[Add a color, file, or image literal](https://help.apple.com/xcode/mac/current/#/dev4c60242fc) - -> 文字表达式的语法: -> -> *literal-expression* → *literal* \ -> *literal-expression* → *array-literal* | *dictionary-literal* | *playground-literal* -> -> *array-literal* → **`[`** *array-literal-items*_?_ **`]`** \ -> *array-literal-items* → *array-literal-item* **`,`**_?_ | *array-literal-item* **`,`** *array-literal-items* \ -> *array-literal-item* → *expression* -> -> *dictionary-literal* → **`[`** *dictionary-literal-items* **`]`** | **`[`** **`:`** **`]`** \ -> *dictionary-literal-items* → *dictionary-literal-item* **`,`**_?_ | *dictionary-literal-item* **`,`** *dictionary-literal-items* \ -> *dictionary-literal-item* → *expression* **`:`** *expression* -> -> *playground-literal* → **`#colorLiteral`** **`(`** **`red`** **`:`** *expression* **`,`** **`green`** **`:`** *expression* **`,`** **`blue`** **`:`** *expression* **`,`** **`alpha`** **`:`** *expression* **`)`** \ -> *playground-literal* → **`#fileLiteral`** **`(`** **`resourceName`** **`:`** *expression* **`)`** \ -> *playground-literal* → **`#imageLiteral`** **`(`** **`resourceName`** **`:`** *expression* **`)`** - -### 自我表达 - -`self`表达式是对当前类型或它所在类型的实例的显式引用。它有以下几种形式: - -```swift -self -self.<#member name#> -self[<#subscript index#>] -self(<#initializer arguments#>) -self.init(<#initializer arguments#>) -``` - - - -在初始值设定项、下标或实例方法中, `self`指的是它出现的类型的当前实例。在类型方法中, `self`指的是它出现的当前类型。 - -`self`表达式用于在访问成员时指定作用域,当作用域中存在另一个同名变量(例如函数参数)时,可以消除歧义。例如: - -```swift -class SomeClass { - var greeting: String - init(greeting: String) { - self.greeting = greeting - } -} -``` - - - -在值类型的变异方法中,您可以将该值类型的新实例分配给 `self` 。例如: - -```swift -struct Point { - var x = 0.0, y = 0.0 - mutating func moveBy(x deltaX: Double, y deltaY: Double) { - self = Point(x: x + deltaX, y: y + deltaY) - } -} -``` - - - - - -> 自我表达的语法: -> -> *self-expression* → **`self`** | *self-method-expression* | *self-subscript-expression* | *self-initializer-expression* -> -> *self-method-expression* → **`self`** **`.`** *identifier* \ -> *self-subscript-expression* → **`self`** **`[`** *function-call-argument-list* **`]`** \ -> *self-initializer-expression* → **`self`** **`.`** **`init`** - -### 超类表达式 - -*超类表达式*允许类与其超类交互。它具有以下形式之一: - -```swift -super.<#member name#> -super[<#subscript index#>] -super.init(<#initializer arguments#>) -``` - -第一种形式用于访问超类的成员。第二种形式用于访问超类的下标实现。第三种形式用于访问超类的初始值设定项。 - -子类可以在其成员、下标和初始化器的实现中使用超类表达式,以利用其超类中的实现。 - -> 超类表达式的语法: -> -> *superclass-expression* → *superclass-method-expression* | *superclass-subscript-expression* | *superclass-initializer-expression* -> -> *superclass-method-expression* → **`super`** **`.`** *identifier* \ -> *superclass-subscript-expression* → **`super`** **`[`** *function-call-argument-list* **`]`** \ -> *superclass-initializer-expression* → **`super`** **`.`** **`init`** - -### 条件表达式 - -*条件表达式*根据条件值计算为多个给定值之一。它具有以下形式之一: - -```swift -if <#condition 1#> { - <#expression used if condition 1 is true#> -} else if <#condition 2#> { - <#expression used if condition 2 is true#> -} else { - <#expression used if both conditions are false#> -} - -switch <#expression#> { -case <#pattern 1#>: - <#expression 1#> -case <#pattern 2#> where <#condition#>: - <#expression 2#> -default: - <#expression 3#> -} -``` - -除了以下段落描述的差异之外,条件表达式与`if`语句或`switch`语句具有相同的行为和语法。 - -条件表达式仅出现在以下上下文中: - -- 作为分配给变量的值。 -- 作为变量或常量声明中的初始值。 -- 作为由 `throw `表达式引发的错​​误。 -- 作为函数、闭包或属性 `getter` 返回的值。 -- 作为条件表达式分支内的值。 - -条件表达式的分支是详尽的,确保无论条件如何,表达式始终生成一个值。这意味着每个if分支都需要一个相应的else分支。 - -每个分支包含一个表达式(当该分支的条件为 true 时用作条件表达式的值)、一个 `throw`语句或对永不返回的函数的调用。 - -每个分支必须产生相同类型的值。由于每个分支的类型检查是独立的,因此有时需要显式指定值的类型,例如当分支包含不同类型的文字时,或者当分支的值为`nil`时。当您需要提供此信息时,请向结果分配到的变量添加类型注释,或向分支的值添加`as`强制转换。 - -```swift -let number: Double = if someCondition { 10 } else { 12.34 } -let number = if someCondition { 10 as Double } else { 12.34 } -``` - -在结果生成器中,条件表达式只能显示为变量或常量的初始值。此行为意味着当您在结果生成器中编写`if`或`switch` 时(在变量或常量声明之外),该代码将被理解为分支语句,并且结果生成器的方法之一会转换该代码。 - -不要将条件表达式放入try表达式中,即使条件表达式的分支之一抛出异常。 - -> 条件句语法: -> -> *conditional-expression* → *if-expression* | *switch-expression* -> -> *if-expression* → **`if`** *condition-list* **`{`** *statement* **`}`** *if-expression-tail* \ -> *if-expression-tail* → **`else`** *if-expression* \ -> *if-expression-tail* → **`else`** **`{`** *statement* **`}`** -> -> *switch-expression* → **`switch`** *expression* **`{`** *switch-expression-cases* **`}`** \ -> *switch-expression-cases* → *switch-expression-case* *switch-expression-cases*_?_ \ -> *switch-expression-case* → *case-label* *statement* \ -> *switch-expression-case* → *default-label* *statement* - -### 闭包表达式 - -闭包表达式创建一个闭包,在其他编程语言中也称为*lambda*或匿名函数。与函数声明一样,闭包包含语句,并且它从其封闭范围捕获常量和变量。它具有以下形式: - -```swift -{ (<#parameters#>) -> <#return type#> in - <#statements#> -} -``` - -这些参数与函数声明中的参数具有相同的形式,如。 - -在闭包表达式中写入`throws`或`async`显式地将闭包标记为抛出或异步。 - -```swift -{ (<#parameters#>) async throws -> <#return type#> in - <#statements#> -} -``` - -如果闭包的主体包含一个`throws`语句或一个未嵌套在具有详尽错误处理的`do`语句内的`try`表达式,则该闭包被理解为抛出。如果抛出闭包仅抛出单一类型的错误,则该闭包被理解为抛出该错误类型;否则,它被理解为抛出 `any Error` 。同样,如果主体包含`await`表达式,则它被理解为异步的。 - -有几种特殊的形式可以让闭包写得更简洁: - - - -- 闭包可以省略其参数类型、返回类型或两者。如果省略参数名称和两种类型,请省略语句前的`in`关键字。如果无法推断省略的类型,则会引发编译时错误。 - -- 闭包可以省略其参数的名称。然后,其参数隐式命名为`$`后跟其位置: `$0` 、 `$1 ` 、 `$2`等。 - -- 仅包含单个表达式的闭包被理解为返回该表达式的值。对周围表达式执行类型推断时,也会考虑该表达式的内容。 - -以下闭包表达式是等效的: - -```swift -myFunction { (x: Int, y: Int) -> Int in - return x + y -} - -myFunction { x, y in - return x + y -} - -myFunction { return $0 + $1 } - -myFunction { $0 + $1 } -``` - - - -有关将闭包作为参数传递给函数的信息,请参阅 . - -闭包表达式可以在不存储在变量或常量中的情况下使用,例如当您立即使用闭包作为函数调用的一部分时。上面代码中传递给`myFunction`闭包表达式就是这种立即使用的示例。因此,闭包表达式是转义还是非转义取决于表达式的周围上下文。如果立即调用闭包表达式或作为非转义函数参数传递,则闭包表达式是非转义的。否则,闭包表达式就会转义。 - -有关转义闭包的更多信息,请参阅文档:. - -#### 捕获列表 - -默认情况下,闭包表达式从其周围范围捕获常量和变量,并对这些值进行强引用。您可以使用捕获列表来显式控制如何在闭包中捕获值。 - -捕获列表写为以逗号分隔的表达式列表,并用方括号括起来,位于参数列表之前。如果使用捕获列表,则即使省略参数名称、参数类型和返回类型,也必须使用`in`关键字。 - -捕获列表中的条目在创建闭包时被初始化。对于捕获列表中的每个条目,常量被初始化为周围范围中具有相同名称的常量或变量的值。例如,在下面的代码中, `a`包含在捕获列表中,但`b`不包含在捕获列表中,这使它们具有不同的行为。 - -```swift -var a = 0 -var b = 0 -let closure = { [a] in - print(a, b) -} - -a = 10 -b = 10 -closure() -// Prints "0 10" -``` - - - -有两种不同的东西,名为`a` ,周围作用域中的变量和闭包作用域中的常量,但只有一个名为`b` 变量。创建闭包时,内部作用域中的`a`会使用外部作用域中a的值进行初始化,但它们的值不会以任何特殊方式连接。这意味着外部作用域中a值的更改不会影响内部作用域中`a`的值,闭包内部a的更改也不会影响闭包外部a的值。相比之下,只有一个名为b的变量——外部作用域中的`b`因此来自闭包内部或外部的更改在两个地方都可见。 - - - -当捕获的变量的类型具有引用语义时,这种区别不可见。例如,下面的代码中有两个名为`x`的东西,外部作用域中的变量和内部作用域中的常量,但由于引用语义,它们都引用同一个对象。 - -```swift -class SimpleClass { - var value: Int = 0 -} -var x = SimpleClass() -var y = SimpleClass() -let closure = { [x] in - print(x.value, y.value) -} - -x.value = 10 -y.value = 10 -closure() -// Prints "10 10" -``` - - - - - - - - - -如果表达式值的类型是类,则可以使用`weak`或`unowned`标记捕获列表中的表达式,以捕获对该表达式值的弱或无主引用。 - -```swift -myFunction { print(self.title) } // implicit strong capture -myFunction { [self] in print(self.title) } // explicit strong capture -myFunction { [weak self] in print(self!.title) } // weak capture -myFunction { [unowned self] in print(self.title) } // unowned capture -``` - - - -您还可以将任意表达式绑定到捕获列表中的命名值。创建闭包时将对表达式求值,并以指定的强度捕获该值。例如: - -```swift -// Weak capture of "self.parent" as "parent" -myFunction { [weak parent = self.parent] in print(parent!.title) } -``` - - - -有关闭包表达式的更多信息和示例,请参阅文档: . -关捕获列表的更多信息和示例,请参阅文档:. - - - -> 闭包表达式的语法: -> -> *closure-expression* → **`{`** *attributes*_?_ *closure-signature*_?_ *statements*_?_ **`}`** -> -> *closure-signature* → *capture-list*_?_ *closure-parameter-clause* **`async`**_?_ *throws-clause*_?_ *function-result*_?_ **`in`** \ -> *closure-signature* → *capture-list* **`in`** -> -> *closure-parameter-clause* → **`(`** **`)`** | **`(`** *closure-parameter-list* **`)`** | *identifier-list* \ -> *closure-parameter-list* → *closure-parameter* | *closure-parameter* **`,`** *closure-parameter-list* \ -> *closure-parameter* → *closure-parameter-name* *type-annotation*_?_ \ -> *closure-parameter* → *closure-parameter-name* *type-annotation* **`...`** \ -> *closure-parameter-name* → *identifier* -> -> *capture-list* → **`[`** *capture-list-items* **`]`** \ -> *capture-list-items* → *capture-list-item* | *capture-list-item* **`,`** *capture-list-items* \ -> *capture-list-item* → *capture-specifier*_?_ *identifier* \ -> *capture-list-item* → *capture-specifier*_?_ *identifier* **`=`** *expression* \ -> *capture-list-item* → *capture-specifier*_?_ *self-expression* \ -> *capture-specifier* → **`weak`** | **`unowned`** | **`unowned(safe)`** | **`unowned(unsafe)`** - -### 隐式成员表达式 - -*隐式成员*表达式是在类型推断可以确定隐含类型的上下文中访问类型成员(例如枚举情况或类型方法)的缩写方式。它具有以下形式: - -```swift -.<#member name#> -``` - -例如: - -```swift -var x = MyEnumeration.someValue -x = .anotherValue -``` - - - -如果推断类型是可选类型,则还可以在隐式成员表达式中使用非可选类型的成员。 - -```swift -var someOptional: MyEnumeration? = .someValue -``` - - - -隐式成员表达式后面可以跟后缀运算符或中列出的其他后缀语法。这称为*链式隐式成员表达式*。尽管所有链接的后缀表达式都具有相同的类型是很常见的,但唯一的要求是整个链接的隐式成员表达式需要可转换为其上下文隐含的类型。具体来说,如果隐含类型是可选类型,则可以使用非可选类型的值,如果隐含类型是类类型,则可以使用其子类之一的值。例如: - -```swift -class SomeClass { - static var shared = SomeClass() - static var sharedSubclass = SomeSubclass() - var a = AnotherClass() -} -class SomeSubclass: SomeClass { } -class AnotherClass { - static var s = SomeClass() - func f() -> SomeClass { return AnotherClass.s } -} -let x: SomeClass = .shared.a.f() -let y: SomeClass? = .shared -let z: SomeClass = .sharedSubclass -``` - - - -在上面的代码中, `x` 的类型与其上下文隐含的类型完全匹配, `y` 的类型可以从 `SomeClass` 转换为 `SomeClass?` ,并且 `z` 的类型可以从 `SomeSubclass` 转换为 `SomeClass` 。 - -> 隐式成员表达式的语法: -> -> *implicit-member-expression* → **`.`** *identifier* \ -> *implicit-member-expression* → **`.`** *identifier* **`.`** *postfix-expression* - - - - - -### 带括号的表达式 - -带括号的表达式由括号包围的表达式组成。您可以使用括号通过显式分组表达式来指定运算的优先级。分组括号不会更改表达式的类型 --- 例如, `(1)` 的类型只是 `Int` - - - -> 括号表达式的语法 -> -> *parenthesized-expression* → **`(`** *expression* **`)`** - -### 元组表达式 - -*元组表达式*由逗号分隔的表达式列表组成,并用括号括起来。每个表达式前面可以有一个可选标识符,用冒号 (`:`) 分隔。它具有以下形式: - -```swift -(<#identifier 1#>: <#expression 1#>, <#identifier 2#>: <#expression 2#>, <#...#>) -``` - -元组表达式中的每个标识符在元组表达式的范围内必须是唯一的。在嵌套元组表达式中,同一嵌套级别的标识符必须是唯一的。例如, `(a: 10, a: 20)` 是无效的,因为标签 `a` 在同一级别出现了两次。然而, `(a: 10, b: (a: 1, x: 2))` 是有效的——虽然 `a`出现了两次,但它在外元组中出现一次,在内元组中出现一次。 - - - -元组表达式可以包含零个表达式,也可以包含两个或多个表达式。括号内的单个表达式是括号表达式。 - -> 注意:Swift 中空元组表达式和空元组类型都写成 `()` 。因为 `Void` 是 `()` 的类型别名,所以您可以使用它来编写空元组类型。然而,像所有类型别名一样, `Void` 始终是一种类型——您不能使用它来编写空元组表达式。 - -> 元组表达式的语法: -> -> *tuple-expression* → **`(`** **`)`** | **`(`** *tuple-element* **`,`** *tuple-element-list* **`)`** \ -> *tuple-element-list* → *tuple-element* | *tuple-element* **`,`** *tuple-element-list* \ -> *tuple-element* → *expression* | *identifier* **`:`** *expression* - -### 通配符表达式 - -*通配符表达式* 用于在赋值期间显式忽略某个值。例如,在以下赋值中,`10` 被分配给x ,20 被忽略: - - - -```swift -(x, _) = (10, 20) -// x is 10, and 20 is ignored -``` - - - -> 通配符表达式的语法: -> -> *wildcard-expression* → **`_`** - -### 宏展开表达式 - -*宏扩展表达式* 由宏名称和后跟括号中的以逗号分隔的宏参数列表组成。宏在编译时展开。宏展开表达式具有以下形式: - -```swift -<#macro name#>(<#macro argument 1#>, <#macro argument 2#>) -``` - -宏扩展表达式不能作为参数的默认值出现,除了 Swift 标准库中的 `file()` 和 `line()` 宏。当用作函数或方法参数的默认值时,这些宏将使用调用站点的源代码位置(而不是它们在函数定义中出现的位置)进行计算。 - -[`file()`]: https://developer.apple.com/documentation/swift/file() -[`line()`]: https://developer.apple.com/documentation/swift/line() - -您可以使用宏表达式来调用独立宏。要调用附加的宏,请使用 中描述的自定义属性语法。独立宏和附加宏都扩展如下: - - -1. Swift 解析源代码以生成抽象语法树(AST)。 - -2. 宏实现接收 AST 节点作为其输入并执行该宏所需的转换。 - -3. 宏实现生成的转换后的 AST 节点将添加到原始 AST 中。 - -每个宏的扩展都是独立且自成体系的。但是,作为性能优化,Swift 可能会启动一个实现宏的外部进程,并重用同一进程来扩展多个宏。当您实现宏时,该代码不得依赖于您的代码之前扩展的宏,或任何其他外部状态(例如当前时间)。 - -对于具有多个角色的嵌套宏和附加宏,会重复展开过程。嵌套宏展开表达式从外向内展开。例如,在下面的代码中, `outerMacro(_:) `首先展开,未展开的对`innerMacro(_:)`调用出现在 `outerMacro(_:)`接收的抽象语法树中。输入 - -```swift -#outerMacro(12, #innerMacro(34), "some text") -``` - -具有多个角色的附加宏将为每个角色扩展一次。每个扩展都接收相同的原始 AST 作为其输入。 Swift 通过收集所有生成的 AST 节点并将它们放在 AST 中相应的位置来形成整体扩展。 - -有关 Swift 中宏的概述,请参阅 . - -> 宏展开表达式的语法: -> -> *macro-expansion-expression* → **`#`** *identifier* *generic-argument-clause*_?_ *function-call-argument-clause*_?_ *trailing-closures*_?_ - -### 键路径表达式 - -*键路径表达式*指的是类型的属性或下标。您可以在动态编程任务中使用键路径表达式,例如键值观察。它们具有以下形式: - -```swift -\<#type name#>.<#path#> -``` - -*类型名称*是具体类型的名称,包括任何泛型参数,例如 `String` 、 `[Int]` 或 `Set` 。 - -该*路径*由属性名称、下标、可选链表达式和强制展开表达式组成。这些关键路径组件中的每一个都可以根据需要以任何顺序重复多次。 - -在编译时,键路径表达式被[`KeyPath`](https://developer.apple.com/documentation/swift/keypath) 类的实例替换。 - -要使用键路径访问值,请将键路径传递给 `subscript(keyPath:)` 下标,该下标适用于所有类型。例如: - - - -```swift -struct SomeStructure { - var someValue: Int -} - -let s = SomeStructure(someValue: 12) -let pathToProperty = \SomeStructure.someValue - -let value = s[keyPath: pathToProperty] -// value is 12 -``` - - - -在类型推断可以确定隐含类型的上下文中,可以省略类型名称。以下代码使用 `\.someProperty` 而不是 `\SomeClass.someProperty` : - -```swift -class SomeClass: NSObject { - @objc dynamic var someProperty: Int - init(someProperty: Int) { - self.someProperty = someProperty - } -} - -let c = SomeClass(someProperty: 10) -c.observe(\.someProperty) { object, change in - // ... -} -``` - - - - +第二类模式用于全模式匹配,这种情况下你试图匹配的值在运行时可能不存在。此类模式包括枚举用例模式、可选模式、表达式模式和类型转换模式。你在 `switch` 语句的 `case` 标签中,`do` 语句的 `catch` 子句中,或者在 `if`、`while`、`guard` 和 `for-in` 语句的 `case` 条件句中使用这类模式。 -该*路径* 可以引用self来创建身份密钥路径 `( \.self )`。身份键路径引用整个实例,因此您可以使用它一步来访问和更改存储在变量中的所有数据。例如: - -```swift -var compoundValue = (a: 1, b: 2) -// Equivalent to compoundValue = (a: 10, b: 20) -compoundValue[keyPath: \.self] = (a: 10, b: 20) -``` - - - -该路径可以包含多个属性名称,以句点分隔,以引用属性值的属性。此代码使用关键路径表达式 `\OuterStructure.outer.someValue` 访问 `OuterStructure` 类型的 `outer` 属性的 `someValue` 属性: - -```swift -struct OuterStructure { - var outer: SomeStructure - init(someValue: Int) { - self.outer = SomeStructure(someValue: someValue) - } -} - -let nested = OuterStructure(someValue: 24) -let nestedKeyPath = \OuterStructure.outer.someValue - -let nestedValue = nested[keyPath: nestedKeyPath] -// nestedValue is 24 -``` - - - -*路径*可以包含使用括号的下标,只要下标的参数类型符合 `Hashable` 协议即可。此示例使用键路径中的下标来访问数组的第二个元素: - -```swift -let greetings = ["hello", "hola", "bonjour", "안녕"] -let myGreeting = greetings[keyPath: \[String].[1]] -// myGreeting is 'hola' -``` - - - - - -下标中使用的值可以是命名值或文字。使用值语义在关键路径中捕获值。以下代码在键路径表达式和闭包中使用变量 `index` 来访问 `greetings` 数组的第三个元素。当 `index` 被修改时,键路径表达式仍然引用第三个元素,而闭包使用新索引。 - -```swift -var index = 2 -let path = \[String].[index] -let fn: ([String]) -> String = { strings in strings[index] } - -print(greetings[keyPath: path]) -// Prints "bonjour" -print(fn(greetings)) -// Prints "bonjour" - -// Setting 'index' to a new value doesn't affect 'path' -index += 1 -print(greetings[keyPath: path]) -// Prints "bonjour" - -// Because 'fn' closes over 'index', it uses the new value -print(fn(greetings)) -// Prints "안녕" -``` - - - -该路径可以使用可选链接和强制展开。此代码在键路径中使用可选链接来访问可选字符串的属性: - -```swift -let firstGreeting: String? = greetings.first -print(firstGreeting?.count as Any) -// Prints "Optional(5)" - -// Do the same thing using a key path. -let count = greetings[keyPath: \[String].first?.count] -print(count as Any) -// Prints "Optional(5)" -``` - - - - - -您可以混合和匹配关键路径的组件来访问深度嵌套在类型中的值。以下代码通过使用组合这些组件的键路径表达式来访问数组字典的不同值和属性。 - -```swift -let interestingNumbers = ["prime": [2, 3, 5, 7, 11, 13, 17], - "triangular": [1, 3, 6, 10, 15, 21, 28], - "hexagonal": [1, 6, 15, 28, 45, 66, 91]] -print(interestingNumbers[keyPath: \[String: [Int]].["prime"]] as Any) -// Prints "Optional([2, 3, 5, 7, 11, 13, 17])" -print(interestingNumbers[keyPath: \[String: [Int]].["prime"]![0]]) -// Prints "2" -print(interestingNumbers[keyPath: \[String: [Int]].["hexagonal"]!.count]) -// Prints "7" -print(interestingNumbers[keyPath: \[String: [Int]].["hexagonal"]!.count.bitWidth]) -// Prints "64" -``` - - - -您可以在通常提供函数或闭包的上下文中使用键路径表达式。具体来说,您可以使用根类型为 `SomeType` 且其路径生成 `Value` 类型的值的键路径表达式,而不是 `(SomeType) -> Value` 类型的函数或闭包。 - -```swift -struct Task { - var description: String - var completed: Bool -} -var toDoList = [ - Task(description: "Practice ping-pong.", completed: false), - Task(description: "Buy a pirate costume.", completed: true), - Task(description: "Visit Boston in the Fall.", completed: false), -] - -// Both approaches below are equivalent. -let descriptions = toDoList.filter(\.completed).map(\.description) -let descriptions2 = toDoList.filter { $0.completed }.map { $0.description } -``` - - - - - -关键路径表达式的任何副作用仅在计算表达式的点进行计算。例如,如果您在关键路径表达式的下标内进行函数调用,则该函数仅在计算表达式时调用一次,而不是每次使用关键路径时都被调用。 - -```swift -func makeIndex() -> Int { - print("Made an index") - return 0 -} -// The line below calls makeIndex(). -let taskKeyPath = \[Task][makeIndex()] -// Prints "Made an index" - -// Using taskKeyPath doesn't call makeIndex() again. -let someTask = toDoList[keyPath: taskKeyPath] -``` - - - -有关在与 Objective-C API 交互的代码中使用关键路径的更多信息,请参阅 [Using Objective-C Runtime Features in Swift](https://developer.apple.com/documentation/swift/using_objective_c_runtime_features_in_swift). -有关键值编码和键值观察的信息,请参阅[Key-Value Coding Programming Guide](https://developer.apple.com/library/content/documentation/Cocoa/Conceptual/KeyValueCoding/index.html#//apple_ref/doc/uid/10000107i) -和 [Key-Value Observing Programming Guide](https://developer.apple.com/library/content/documentation/Cocoa/Conceptual/KeyValueObserving/KeyValueObserving.html#//apple_ref/doc/uid/10000177i). - -> 键路径表达式的语法: -> -> *key-path-expression* → **`\`** *type*_?_ **`.`** *key-path-components* \ -> *key-path-components* → *key-path-component* | *key-path-component* **`.`** *key-path-components* \ -> *key-path-component* → *identifier* *key-path-postfixes*_?_ | *key-path-postfixes* +> 模式语法: > -> *key-path-postfixes* → *key-path-postfix* *key-path-postfixes*_?_ \ -> *key-path-postfix* → **`?`** | **`!`** | **`self`** | **`[`** *function-call-argument-list* **`]`** +> *pattern* → *wildcard-pattern* *type-annotation*_?_ \ +> *pattern* → *identifier-pattern* *type-annotation*_?_ \ +> *pattern* → *value-binding-pattern* \ +> *pattern* → *tuple-pattern* *type-annotation*_?_ \ +> *pattern* → *enum-case-pattern* \ +> *pattern* → *optional-pattern* \ +> *pattern* → *type-casting-pattern* \ +> *pattern* → *expression-pattern* -### 选择器表达式 +## 通配符模式 -选择器表达式允许您访问用于引用 Objective-C 中的方法或属性的 getter 或 setter 的选择器。它具有以下形式: +*通配符模式*由一个下划线(`_`)构成,用于匹配并忽略任何值。当你想忽略被匹配的值时可以使用该模式。例如,下面这段代码在闭区间 1...3 中迭代,每次迭代都忽略该区间的当前值: ```swift -#selector(<#method name#>) -#selector(getter: <#property name#>) -#selector(setter: <#property name#>) -``` - -方法名称和属性名称必须是对 Objective-C 运行时中可用的方法或属性的引用。选择器表达式的值是 `Selector` 类型的实例。例如: - -```swift -class SomeClass: NSObject { - @objc let property: String - - @objc(doSomethingWithInt:) - func doSomething(_ x: Int) { } - - init(property: String) { - self.property = property - } -} -let selectorForMethod = #selector(SomeClass.doSomething(_:)) -let selectorForPropertyGetter = #selector(getter: SomeClass.property) -``` - - - -为属性的 getter 创建选择器时,*属性名称*可以是对变量或常量属性的引用。相反,当为属性的设置器创建选择器时,*属性名称* 必须仅是对变量属性的引用。 - -*方法名称*可以包含用于分组的括号,以及用于消除共享名称但具有不同类型签名的方法之间的歧义的 `as`运算符。例如: - -```swift -extension SomeClass { - @objc(doSomethingWithString:) - func doSomething(_ x: String) { } +for _ in 1...3 { + // Do something three times. } -let anotherSelector = #selector(SomeClass.doSomething(_:) as (SomeClass) -> (String) -> Void) ``` - - -因为选择器是在编译时创建的,而不是在运行时创建的,所以编译器可以检查方法或属性是否存在以及它们是否暴露给 Objective-C 运行时。 - -> 注意:虽然*方法名称*和*属性名称*是表达式,但它们永远不会被求值 - -有关在与 Objective-C API 交互的 Swift 代码中使用选择器的更多信息,请参阅[Using Objective-C Runtime Features in Swift](https://developer.apple.com/documentation/swift/using_objective_c_runtime_features_in_swift). - -> 选择器表达式的语法: +> 通配符模式的语法: > -> *selector-expression* → **`#selector`** **`(`** *expression* **`)`** \ -> *selector-expression* → **`#selector`** **`(`** **`getter:`** *expression* **`)`** \ -> *selector-expression* → **`#selector`** **`(`** **`setter:`** *expression* **`)`** - - +> *wildcard-pattern* → **`_`** -### 键路径字符串表达式 +## 标识符模式 -键路径字符串表达式允许您访问用于引用 Objective-C 中的属性的字符串,以用于键值编码和键值观察 API。它具有以下形式: +*标识符模式*匹配任何值,并将匹配的值和一个变量或常量绑定起来。例如,在下面的常量声明中,`someValue` 是一个标识符模式,匹配了 `Int` 类型的 `42`: ```swift -#keyPath(<#property name#>) +let someValue = 42 ``` +当匹配成功时,值 `42` 被绑定(分配)到常量名称 `someValue` . -*属性名称*必须是对 Objective-C 运行时中可用的属性的引用。在编译时,键路径字符串表达式被替换为字符串文字。例如: - -```swift -class SomeClass: NSObject { - @objc var someProperty: Int - init(someProperty: Int) { - self.someProperty = someProperty - } -} - -let c = SomeClass(someProperty: 12) -let keyPath = #keyPath(SomeClass.someProperty) +如果一个变量或常量声明的左边是一个标识符模式,那么这个标识符模式是值绑定模式的子模式。 -if let value = c.value(forKey: keyPath) { - print(value) -} -// Prints "12" -``` +> 标识符模式语法 +> +> *identifier-pattern* → *identifier* - +*值绑定模式*把匹配到的值绑定给一个变量或常量。把匹配到的值绑定给常量时,用关键字 `let`,绑定给变量时,用关键字 `var`。 -当您在类中使用键路径字符串表达式时,您可以通过仅编写属性名称而不编写类名称来引用该类的属性。 +在值绑定模式中的标识符模式会把新命名的变量或常量与匹配到的值做绑定。例如,你可以拆开一个元组,然后把每个元素绑定到相应的标识符模式中。 ```swift -extension SomeClass { - func getSomeKeyPath() -> String { - return #keyPath(someProperty) - } +let point = (3, 2) +switch point { +// 将 point 中的元素绑定到 x 和 y +case let (x, y): + print("The point is at (\(x), \(y)).") } -print(keyPath == c.getSomeKeyPath()) -// Prints "true" +// 打印 "The point is at (3, 2)." ``` - - -由于关键路径字符串是在编译时而不是运行时创建的,因此编译器可以检查该属性是否存在以及该属性是否公开给 Objective-C 运行时。 - -有关在与 Objective-C API 交互的 Swift 代码中使用关键路径的更多信息,请参阅[Using Objective-C Runtime Features in Swift](https://developer.apple.com/documentation/swift/using_objective_c_runtime_features_in_swift)。 -有关键值编码和键值观察的信息,请参阅 [Key-Value Coding Programming Guide](https://developer.apple.com/library/content/documentation/Cocoa/Conceptual/KeyValueCoding/index.html#//apple_ref/doc/uid/10000107i) -和 [Key-Value Observing Programming Guide](https://developer.apple.com/library/content/documentation/Cocoa/Conceptual/KeyValueObserving/KeyValueObserving.html#//apple_ref/doc/uid/10000177i)。 - -> 注意:虽然*属性名称*是一个表达式,但它永远不会被计算。 - -> 键路径字符串表达式的语法: -> -> *键路径字符串表达式* → **`#keyPath`** **`(`** *表达式* **`)`** - -## 后缀表达式 - -*后缀表达式*是通过对表达式应用后缀运算符或其他后缀语法来形成的。从语法上来说,每个主表达式也是一个后缀表达式。 - -有关这些运算符的行为的信息,请参阅。 +在上面的示例中, `let` 分配给元组模式`(x, y)` 中的每个标识符模式。因此, `switch` 语句中 `case let (x, y):` 和 `case (let x, let y):` 的匹配效果是一样的。 -有关 Swift 标准库提供的运算符的信息,请参阅[Operator Declarations](https://developer.apple.com/documentation/swift/operator_declarations)。 - -> 后缀表达式的语法: +> 值绑定模式语法 > -> *postfix-expression* → *primary-expression* \ -> *postfix-expression* → *postfix-expression* *postfix-operator* \ -> *postfix-expression* → *function-call-expression* \ -> *postfix-expression* → *initializer-expression* \ -> *postfix-expression* → *explicit-member-expression* \ -> *postfix-expression* → *postfix-self-expression* \ -> *postfix-expression* → *subscript-expression* \ -> *postfix-expression* → *forced-value-expression* \ -> *postfix-expression* → *optional-chaining-expression* - -### 函数调用表达式 - - - -函数调用*表达式*由函数名称和后跟括号中的以逗号分隔的函数参数列表组成。函数调用表达式具有以下形式: - -```swift -<#function name#>(<#argument value 1#>, <#argument value 2#>) -``` - -*函数名称*可函数名可以是任何其值是函数类型的表达式。 - -如果函数定义包含其参数名称,则函数调用必须在其参数值之前包含名称,并用冒号(`:`)分隔。 -这种函数调用表达式具有以下形式: - -```swift -<#function name#>(<#argument name 1#>: <#argument value 1#>, <#argument name 2#>: <#argument value 2#>) -``` - -函数调用表达式可以在紧跟在右括号之后以闭包表达式的形式包含尾随闭包。尾随闭包被理解为函数的参数,添加在最后一个带括号的参数之后。第一个闭包表达式是无标签的;任何其他闭包表达式前面都有其参数标签。下面的示例显示了使用和不使用尾随闭包语法的函数调用的等效版本: - -```swift -// someFunction takes an integer and a closure as its arguments -someFunction(x: x, f: { $0 == 13 }) -someFunction(x: x) { $0 == 13 } - -// anotherFunction takes an integer and two closures as its arguments -anotherFunction(x: x, f: { $0 == 13 }, g: { print(99) }) -anotherFunction(x: x) { $0 == 13 } g: { print(99) } -``` - - - - - -如果尾随闭包是函数的唯一参数,则可以省略括号。 - -```swift -// someMethod takes a closure as its only argument -myData.someMethod() { $0 == 13 } -myData.someMethod { $0 == 13 } -``` - - - - - -为了在参数中包含尾随闭包,编译器从左到右检查函数的参数,如下所示: +> *value-binding-pattern* → **`var`** *pattern* | **`let`** *pattern* -| 尾随闭包 | 范围 | 行动 | -| ---------------- | --------- | ------ | -| 贴上标签 | 贴上标签 | 如果标签相同,则闭包与参数匹配;否则,该参数将被跳过。| -| 贴上标签 | 未标记 | 该参数被跳过。 | -| 未标记 | 有标签或无标签 | 如果参数在结构上类似于函数类型(如下定义),则闭包与参数匹配;否则,该参数将被跳过。 | +## 元组模式 -尾随闭包作为其匹配参数的参数传递。在扫描过程中跳过的参数没有传递给它们的参数——例如,它们可以使用默认参数。找到匹配项后,将继续扫描下一个尾随闭包和下一个参数。在匹配过程结束时,所有尾随闭包都必须有匹配项。 +*元组模式*是由逗号分隔的,具有零个或多个模式的列表,并由一对圆括号括起来。元组模式匹配相应元组类型的值。 -如果参数不是输入输出参数,并且参数是以下之一,则该参数在结构上类似于函数类型: +你可以使用类型注解去限制一个元组模式能匹配哪种元组类型。例如,在常量声明 let (x, y): (Int, Int) = (1, 2) 中的元组模式 (x, y): (Int, Int) 只匹配两个元素都是 Int 类型的元组。 -- 类型为函数类型的参数,如`(Bool) -> Int` -- 一个自动闭包参数,其包装表达式的类型是函数类型,例如 `@autoclosure () -> ((Bool) -> Int)` -- 数组元素类型为函数类型的可变参数,例如`((Bool) -> Int)...` -- 其类型被包裹在一层或多层可选中的参数,例如`Optional<(Bool) -> Int>` -- 其类型组合了这些允许类型的参数,例如 `(Optional<(Bool) -> Int>)...` - -当尾随闭包与结构上类似于函数类型但不是函数的参数匹配时,闭包将根据需要进行包装。例如,如果参数的类型是可选类型,则闭包会自动包装在 `Optional` 中. - - - -为了简化从 5.3 之前的 Swift 版本(执行从右到左的匹配)的代码迁移,编译器会检查从左到右和从右到左的顺序。如果扫描方向产生不同的结果,则使用旧的从右到左排序,并且编译器会生成警告。 Swift 的未来版本将始终使用从左到右的排序。 +当元组模式用作 `for-in` 语句或变量或常量声明中的模式时,它只能包含通配符模式、标识符模式、可选模式或包含这些模式的其他元组模式。例如,以下代码无效,因为元组模式 `(x, 0)` 中的元素 `0` 是表达式模式: ```swift -typealias Callback = (Int) -> Int -func someFunction(firstClosure: Callback? = nil, - secondClosure: Callback? = nil) { - let first = firstClosure?(10) - let second = secondClosure?(20) - print(first ?? "-", second ?? "-") +let points = [(0, 0), (1, 0), (1, 1), (2, 0), (2, 1)] +// 下面的代码是错误的 +for (x, 0) in points { + /* ... */ } - -someFunction() // Prints "- -" -someFunction { return $0 + 100 } // Ambiguous -someFunction { return $0 } secondClosure: { return $0 } // Prints "10 20" ``` - - -在上面的示例中,标记为“Ambigitude”的函数调用会打印“- 120”,并在 Swift 5.3 上生成编译器警告。 Swift 的未来版本将打印“110 -”。 - - +只包含一个元素的元组模式的圆括号没有效果,模式只匹配这个单个元素的类型。举例来说,下面的语句是等效的: -类、结构或枚举类型可以通过声明多种方法之一来启用函数调用语法的语法糖,如 中所述。 - -#### 隐式转换为指针类型 - -在函数调用表达式中,如果参数和参数具有不同的类型,编译器会尝试通过应用以下列表中的隐式转换之一来使它们的类型匹配: - -- `inout SomeType` 可以成为 -`UnsafePointer` 或 `UnsafeMutablePointer` -- `inout Array` 可以成为 -`UnsafePointer`或`UnsafeMutablePointer` -- `Array`可以成为`UnsafePointer` -- `String`可以成为`UnsafePointer` - -以下两个函数调用是等效的: ```swift -func unsafeFunction(pointer: UnsafePointer) { - // ... -} -var myNumber = 1234 - -unsafeFunction(pointer: &myNumber) -withUnsafePointer(to: myNumber) { unsafeFunction(pointer: $0) } +let a = 2 // a: Int = 2 +let (a) = 2 // a: Int = 2 +let (a): Int = 2 // a: Int = 2 ``` - - -通过这些隐式转换创建的指针仅在函数调用期间有效。为了避免未定义的行为,请确保您的代码在函数调用结束后永远不会保留指针。 - -> 当将数组隐式转换为不安全指针时,Swift 通过根据需要转换或复制数组来确保数组的存储是连续的。例如,您可以将此语法与从 `NSArray` 子类桥接到 `Array` 的数组一起使用,该子类不对其存储制定任何 API 约定。如果您需要保证数组的存储已经是连续的,因此隐式转换永远不需要执行此工作,请使用 `ContiguousArray` 而不是 `Array` 。 - -使用`&`而不是像`withUnsafePointer(to:)`这样的显式函数可以帮助提高对低级 C 函数的调用的可读性,特别是当函数采用多个指针参数时。但是,当从其他 Swift 代码调用函数时,请避免使用`&`而应显式使用不安全的 API。 - - - -> 函数调用表达式的语法: -> -> *function-call-expression* → *postfix-expression* *function-call-argument-clause* \ -> *function-call-expression* → *postfix-expression* *function-call-argument-clause*_?_ *trailing-closures* +> 元组模式语法: > -> *function-call-argument-clause* → **`(`** **`)`** | **`(`** *function-call-argument-list* **`)`** \ -> *function-call-argument-list* → *function-call-argument* | *function-call-argument* **`,`** *function-call-argument-list* \ -> *function-call-argument* → *expression* | *identifier* **`:`** *expression* \ -> *function-call-argument* → *operator* | *identifier* **`:`** *operator* -> -> *trailing-closures* → *closure-expression* *labeled-trailing-closures*_?_ \ -> *labeled-trailing-closures* → *labeled-trailing-closure* *labeled-trailing-closures*_?_ \ -> *labeled-trailing-closure* → *identifier* **`:`** *closure-expression* +> *tuple-pattern* → **`(`** *tuple-pattern-element-list*_?_ **`)`** \ +> *tuple-pattern-element-list* → *tuple-pattern-element* | *tuple-pattern-element* **`,`** *tuple-pattern-element-list* \ +> *tuple-pattern-element* → *pattern* | *identifier* **`:`** *pattern* -### 初始化表达式 +## 枚举用例模式 -初始值设定项表达式提供对类型的初始值设定项的访问。它具有以下形式: +*枚举用例模式*匹配现有的某个枚举类型的某个用例。枚举用例模式出现在 `switch` 语句中的 `case` 标签中,以及 `if`、`while`、`guard` 和 `for-in` 语句的 `case` 条件中。 -```swift -<#expression#>.init(<#initializer arguments#>) -``` +如果你准备匹配的枚举用例有任何关联的值,则相应的枚举用例模式必须指定一个包含每个关联值元素的元组模式。关于使用 `switch` 语句来匹配包含关联值的枚举用例的例子,请参阅. -您可以在函数调用表达式中使用初始化表达式来初始化类型的新实例。您还可以使用初始值设定项表达式来委托给超类的初始值设定项。 +枚举用例模式同样会匹配那些被包装成可选值的用例。简化的语法能将可选模式过滤掉。注意,由于 `Optional` 是枚举实现的,`.none` 和 `.some` 都会作为枚举类型的用例出现在 switch 中。 ```swift -class SomeSubClass: SomeSuperClass { - override init() { - // subclass initialization goes here - super.init() - } +enum SomeEnum { case left, right } +let x: SomeEnum? = .left +switch x { +case .left: + print("Turn left") +case .right: + print("Turn right") +case nil: + print("Keep going straight") } +// 打印 "Turn left" ``` - - -与函数一样,初始化器可以用作值。例如: - -```swift -// Type annotation is required because String has multiple initializers. -let initializer: (Int) -> String = String.init -let oneTwoThree = [1, 2, 3].map(initializer).reduce("", +) -print(oneTwoThree) -// Prints "123" -``` - - - -如果按名称指定类型,则可以访问该类型的初始值设定项,而无需使用初始值设定项表达式。在所有其他情况下,您必须使用初始化表达式。 - -```swift -let s1 = SomeType.init(data: 3) // Valid -let s2 = SomeType(data: 1) // Also valid - -let s3 = type(of: someValue).init(data: 7) // Valid -let s4 = type(of: someValue)(data: 5) // Error -``` - - - -> 初始化表达式的语法: +> 枚举用例模式语法: > -> *initializer-expression* → *postfix-expression* **`.`** **`init`** \ -> *initializer-expression* → *postfix-expression* **`.`** **`init`** **`(`** *argument-names* **`)`** +> *enum-case-pattern* → *type-identifier*_?_ **`.`** *enum-case-name* *tuple-pattern*_?_ -### 显式成员表达式 +## 可选模式 -*显式成员表达式*允许访问命名类型、元组或模块的成员。它由项目与其成员标识符之间的句点 ( `.` ) 组成。 +可选模式匹配包装在一个 `Optional(Wrapped)` 或者 `ExplicitlyUnwrappedOptional(Wrapped)` 枚举中的 `Some(Wrapped)` 用例中的值。可选模式由一个标识符模式和紧随其后的一个问号组成,可以像枚举用例模式一样使用。 -```swift -<#expression#>.<#member name#> -``` - -命名类型的成员被命名为类型声明或扩展的一部分。例如: +由于可选模式是 `Optional` 和 `ImplicitlyUnwrappedOptional` 枚举用例模式的语法糖,下面两种写法是等效的: ```swift -class SomeClass { - var someProperty = 42 +let someOptional: Int? = 42 +// 使用枚举用例模式匹配 +if case .some(let x) = someOptional { + print(x) } -let c = SomeClass() -let y = c.someProperty // Member access -``` - - - -元组的成员按照它们出现的顺序使用整数隐式命名,从零开始。例如: - -```swift -var t = (10, 20, 30) -t.0 = t.1 -// Now t is (20, 20, 30) -``` - - - -模块的成员访问该模块的顶级声明。 - -使用`dynamicMemberLookup`属性声明的类型包括在运行时查找的成员,如 中所述。 - -为了区分名称仅因参数名称而不同的方法或初始化器, - -要区分名称仅因参数名称不同的方法或初始值设定项,请将参数名称包含在括号中,每个参数名称后跟一个冒号 `:` )。为没有名称的参数写入下划线 ( `_` )。要区分重载方法,请使用类型注释。例如: -```swift -class SomeClass { - func someMethod(x: Int, y: Int) {} - func someMethod(x: Int, z: Int) {} - func overloadedMethod(x: Int, y: Int) {} - func overloadedMethod(x: Int, y: Bool) {} +// 使用可选模式匹配 +if case let x? = someOptional { + print(x) } -let instance = SomeClass() - -let a = instance.someMethod // Ambiguous -let b = instance.someMethod(x:y:) // Unambiguous - -let d = instance.overloadedMethod // Ambiguous -let d = instance.overloadedMethod(x:y:) // Still ambiguous -let d: (Int, Bool) -> Void = instance.overloadedMethod(x:y:) // Unambiguous -``` - - - -如果句点出现在行的开头,则它将被理解为显式成员表达式的一部分,而不是隐式成员表达式。例如,以下清单显示了分为几行的链式方法调用: - -```swift -let x = [10, 3, 20, 15, 4] - .sorted() - .filter { $0 > 5 } - .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`和其他编译指令之间,条件编译块可以包含隐式成员表达式,后跟零个或多个后缀,以形成后缀表达式。它还可以包含另一个条件编译块,或这些表达式和块的组合。 - -您可以在任何可以编写显式成员表达式的地方使用此语法,而不仅仅是在顶级代码中。 - -在条件编译块中, `#if` 编译指令的分支必须至少包含一个表达式。其他分支可以为空。 - - - - - - - -> 显式成员表达式的语法: -> -> *explicit-member-expression* → *postfix-expression* **`.`** *decimal-digits* \ -> *explicit-member-expression* → *postfix-expression* **`.`** *identifier* *generic-argument-clause*_?_ \ -> *explicit-member-expression* → *postfix-expression* **`.`** *identifier* **`(`** *argument-names* **`)`** \ -> *explicit-member-expression* → *postfix-expression* *conditional-compilation-block* -> -> *argument-names* → *argument-name* *argument-names*_?_ \ -> *argument-name* → *identifier* **`:`** - - - - - -### 自我表达 - -后缀`self` 表达式由表达式或类型名称组成,后跟 `.self` 。它有以下几种形式: - -```swift -<#expression#>.self -<#type#>.self ``` -第一种形式计算表达式的值。例如, `x.self` 计算结果为 `x` 。 - -第二种形式求值为*type*的值。使用此形式将类型作为值进行访问。例如,由于 `SomeClass.self` 计算结果为 `SomeClass` 类型本身,因此您可以将其传递给接受类型级参数的函数或方法。 - -> 后缀自我表达的语法: -> -> *postfix-self-expression* → *postfix-expression* **`.`** **`self`** - -### 下标表达式 - -*下标表达式*使用相应下标声明的 getter 和 setter 提供下标访问。它具有以下形式: +可选模式为 `for-in` 语句提供了一种迭代数组的简便方式,只为数组中非 `nil` 的元素执行循环体。 ```swift -<#expression#>[<#index expressions#>] +let arrayOfOptionalInts: [Int?] = [nil, 2, 3, nil, 5] +// 只匹配非 nil 的元素 +for case let number? in arrayOfOptionalInts { + print("Found a \(number)") +} +// Found a 2 +// Found a 3 +// Found a 5 ``` -为了计算下标表达式的值,需要调用表达式类型的下标 getter,并将索引表达式作为下标参数传递。为了设置它的值,以同样的方式调用下标设置器。 - - - -有关下标声明的信息,请参阅 . - -> 下标表达式的语法: +> 可选模式语法: > -> *subscript-expression* → *postfix-expression* **`[`** *function-call-argument-list* **`]`** - - +## 类型转换模式 -### 强制值表达 - -*强制值表达式*会解包您确定不是 `nil` 的可选值。它具有以下形式: +有两种类型转换模式: `is` 模式和`as` 模式。 `is` 模式仅出现在`switch` 语句 case 标签中. `is` 和 `as` 模式具有以下形式: ```swift -<#expression#>! +is <#类型#> +<#pattern#> as <#type#> ``` -如果表达式的值不是 `nil` ,则可选值将被解包并以相应的非可选类型返回。否则,会引发运行时错误。 - -可以通过改变值本身或分配给值的成员之一来修改强制值表达式的展开值。例如: +`is` 模式仅当一个值的类型在运行时和 `is` 模式右边的指定类型一致,或者是其子类的情况下,才会匹配这个值。`is` 模式和 `is` 运算符有相似表现,它们都进行类型转换,但是 `is` 模式没有返回类型。 -```swift -var x: Int? = 0 -x! += 1 -// x is now 1 - -var someDictionary = ["a": [1, 2, 3], "b": [10, 20]] -someDictionary["a"]![0] = 100 -// someDictionary is now ["a": [100, 2, 3], "b": [10, 20]] -``` - - +关于使用 `switch` 语句配合 `is` 模式和 `as` 模式来匹配值的例子,请参阅. -> 强制值表达式的语法: +> 类型转换模式语法 > -> *强制值表达式* → *后缀表达式* **`!`** - -### 可选链式表达式 - -*可选链表达式*提供了在后缀表达式中使用可选值的简化语法。它具有以下形式: - -```swift -<#expression#>? -``` - -后缀 `?` 运算符从表达式创建可选链表达式而不更改表达式的值。 - -可选链表达式必须出现在后缀表达式中,并且它们会导致后缀表达式以特殊方式进行计算。如果可选链表达式的值为 `nil` ,则后缀表达式中的所有其他操作都将被忽略,并且整个后缀表达式的计算结果为 `nil` 。如果可选链表达式的值不是 `nil` ,则可选链表达式的值将被展开并用于计算后缀表达式的其余部分。无论哪种情况,后缀表达式的值仍然是可选类型。 - -如果包含可选链表达式的后缀表达式嵌套在其他后缀表达式中,则只有最外面的表达式返回可选类型。在下面的示例中,当 `c `不为 `nil`时,其值将被展开并用于计算 `.property` ,其值用于计算 `.performAction()` 。整个表达式 `c?.property.performAction()`具有可选类型的值。 +> *type-casting-pattern* → *is-pattern* | *as-pattern* \ +> *is-pattern* → **`is`** *type* \ +> *as-pattern* → *pattern* **`as`** *type* -```swift -var c: SomeClass? -var result: Bool? = c?.property.performAction() -``` +## 表达式模式 - - -以下示例显示了上面示例的行为,而不使用可选链。 +表达式模式代表的表达式会使用 Swift 标准库中的 `~=` 运算符与输入表达式的值进行比较。如果 `~=` 运算符返回 `true`,则匹配成功。默认情况下,`~=` 运算符使用 `==` 运算符来比较两个相同类型的值。它也可以将一个整型数值与一个 Range 实例中的一段整数区间做匹配,正如下面这个例子所示: ```swift -var result: Bool? -if let unwrappedC = c { - result = unwrappedC.property.performAction() +let point = (1, 2) +switch point { +case (0, 0): + print("(0, 0) is at the origin.") +case (-2...2, -2...2): + print("(\(point.0), \(point.1)) is near the origin.") +default: + print("The point is at (\(point.0), \(point.1)).") } +// 打印"(1, 2) is near the origin." ``` - - -可以通过改变值本身或分配给值的成员之一来修改可选链表达式的展开值。如果可选链表达式的值为nil ,则不计算赋值运算符右侧的表达式。例如: +你可以重载 `~=` 运算符来提供自定义的表达式匹配行为。比如你可以重写上面的例子,将 `point` 表达式与字符串形式表示的点进行比较。 ```swift -func someFunctionWithSideEffects() -> Int { - return 42 // No actual side effects. +// 重载 ~= 运算符对字符串和整数进行比较 +func ~= (pattern: String, value: Int) -> Bool { + return pattern == "\(value)" } -var someDictionary = ["a": [1, 2, 3], "b": [10, 20]] - -someDictionary["not here"]?[0] = someFunctionWithSideEffects() -// someFunctionWithSideEffects isn't evaluated -// someDictionary is still ["a": [1, 2, 3], "b": [10, 20]] - -someDictionary["a"]?[0] = someFunctionWithSideEffects() -// someFunctionWithSideEffects is evaluated and returns 42 -// someDictionary is now ["a": [42, 2, 3], "b": [10, 20]] +switch point { +case ("0", "0"): + print("(0, 0) is at the origin.") +default: + print("The point is at (\(point.0), \(point.1)).") +} +// 打印 "The point is at (1, 2)." ``` - - -> 可选链表达式的语法: +> 表达式模式语法: > -> *optional-chaining-expression* → *postfix-expression* **`?`** +> *expression-pattern* → *expression* > 测试版软件: > -> 本文档包含有关正在开发的 API 或技术的初步信息。该信息可能会发生变化,并且根据本文档实现的软件应使用最终操作系统软件进行测试。. +> 本文档包含有关正在开发的 API 或技术的初步信息。该信息可能会发生变化,并且根据本文档实现的软件应使用最终操作系统软件进行测试. > -> 了解更多关于使用 [Apple's beta software](https://developer.apple.com/support/beta-software/). +> 了解有关使用 [Apple 测试软件的](https://developer.apple.com/support/beta-software/)更多信息. From 146f0b0c20a9b2f190edc91e68298c35564031f1 Mon Sep 17 00:00:00 2001 From: King <66349714+king-open@users.noreply.github.com> Date: Sun, 20 Oct 2024 21:48:24 +0800 Subject: [PATCH 12/14] =?UTF-8?q?docs=EF=BC=9A=E5=8F=82=E8=80=83=E5=BB=BA?= =?UTF-8?q?=E8=AE=AE=20Expressions.md?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../ReferenceManual/Expressions.md | 741 ++++++++---------- 1 file changed, 320 insertions(+), 421 deletions(-) diff --git a/swift-6-beta.docc/ReferenceManual/Expressions.md b/swift-6-beta.docc/ReferenceManual/Expressions.md index 83e576c07..a6610eb74 100644 --- a/swift-6-beta.docc/ReferenceManual/Expressions.md +++ b/swift-6-beta.docc/ReferenceManual/Expressions.md @@ -8,65 +8,67 @@ Swift 中存在四种表达式:前缀表达式,中缀表达式,基本表 > 表达式语法: > -> *表达式语法* → *try 运算符*_?_ *await运算符*_?_ *前缀表达式* *中缀表达式*_?_ \ +> *expression* → *try-operator*_?_ *await-operator*_?_ *prefix-expression* *infix-expressions*_?_ \ -## 前缀表达式 +## 前缀表达式 前缀表达式由可选的前缀运算符和表达式组成。前缀运算符只接收一个参数,表达式则紧随其后。 -关于这些运算符的更多信息,请参阅。 +关于这些运算符的更多信息,请参阅 . -关于 Swift 标准库提供的运算符的更多信息,请参阅[Operator Declarations](https://developer.apple.com/documentation/swift/operator_declarations)。 +关于 Swift 标准库提供的运算符的更多信息,请参阅 [Operator Declarations](https://developer.apple.com/documentation/swift/operator_declarations). -> 前缀表达式语法: +> 前缀表达式语法 > -> *前缀表达式* → *前缀运算符*_?_ *后缀表达式* \ -> *前缀表达式* → *输入输出表达式* +> *prefix-expression* → *prefix-operator*_?_ *postfix-expression* \ +> *prefix-expression* → *in-out-expression* -### 输入输出表达式 +### In-Out 表达式 -输入输出表达式 将函数调用表达式传入的变量标记为输入输出实参。 + *in-out表达式*将函数调用表达式传入的变量标记为输入输出实参。 ```swift &<#表达式#> ``` -更多关于输入输出形参的信息和例子,请参阅. +输入输出表达式也可以用于将非指针实参传入到需要指针的上下文中,如 . -输入输出表达式也可以用于将非指针实参传入到需要指针的上下文中,如 中所述。 +In-out 表达式也可以用于将非指针实参传入到需要指针的上下文中,如 . -> 输入输出表达式语法: +> Grammar of an in-out expression: > -> *输入输出表达式* → **`&`** *标识符* +> *in-out-expression* → **`&`** *标识符* ### Try 运算符 - try 表达式由`try` 运算符加上紧随其后的可抛出错误的表达式组成,形式如下: +*try表达式*由 `try` 运算符加上紧随其后的可抛出错误的表达式组成,形式如下: ```swift try <#表达式#> ``` -`try` 表达式的返回值是该*表达式*的值。 -可选的 try 表达式由`try?` 运算符加上紧随其后的可抛出错误的表达式组成,形式如下: +`try` 表达式的返回值是该表达式的值。 +*可选 try* 表达式由 `try?` 运算符加上紧随其后的可抛出错误的表达式组成,形式如下: ```swift try? <#表达式#> ``` -如果表达式没有抛出错误,可选 try 表达式的返回值是可选的该表达式的值,否则,返回值为 `nil`。 +如果*表达式*没有抛出错误,可选 try 表达式的返回值是可选的该表达式的值,否则,返回值为 `nil`。 -强制 try 表达式由 `try!` 运算符加上紧随其后的可抛出错误的表达式组成,形式如下: +*强制 try 表达式*由 `try!` 运算符加上紧随其后的可抛出错误的表达式组成,形式如下: ```swift try! <#表达式#> ``` -强制 try 表达式的返回值是该表达式的值。如果该表达式抛出了错误,将会引发运行时错误。 +强制 try 表达式的返回值是该*表达式*的值。如果该*表达式*抛出了错误,将会引发运行时错误。 在中缀运算符左侧的表达式被标记上 `try`、`try?` 或者 `try!` 时,这个运算符对整个中缀表达式都产生作用。也就是说,你可以使用括号来明确运算符的作用范围。 + + ```swift // try 对两个函数调用都产生作用 sum = try someThrowingFunction() + anotherThrowingFunction() @@ -78,30 +80,36 @@ sum = try (someThrowingFunction() + anotherThrowingFunction()) sum = (try someThrowingFunction()) + anotherThrowingFunction() ``` -`try` 表达式不能出现在中缀运算符的的右侧,除非中缀运算符是赋值运算符或者 `try`表达式是被圆括号括起来的。 - -如果表达式同时包含`try`和`await`运算符,则`try`运算符必须在前面。 +`try` 表达式不能出现在中缀运算符的的右侧,除非中缀运算符是赋值运算符或者 `try` 表达式是被圆括号括起来的。 +如果表达式中同时包含 `try` 和 `await` 运算符,`try` 运算符必须在前面。 -更多关于`try`、`try?`的示例,并 `try!` 的信息,以及该如何使用的例子,请参阅 . +更多关于 `try`、`try?` 和 `try!` 的信息,以及该如何使用的例子,请参阅 . -> try 表达式语法: +> Try 表达式语法 > -> *try-运算符* → **`try`** | **`try`** **`?`** | **`try`** **`!`** +> *try运算符* → **`try`** | **`try`** **`?`** | **`try`** **`!`** ### Await 运算符 -*await* 表达式由`await` 运算符加上紧随其后的异步操作结果的表达式。形式如下: + *await表达式*由 await 运算符加上紧随其后的异步操作结果的表达式。形式如下: ```swift await <#表达式#> ``` -`await`表达式返回值就是该*表达式*的值。被 `await` 标记的表达式被称为潜在的暂停点。 异步函数的执行可以在每个标记 `await` 的表达式的位置暂停。除此之外,并发代码的执行永远不会在其他位置暂停。这意味着在潜在暂停点之间的代码可以暂时打破不变量的状态进行安全更新,只要更新在下一个潜在暂停点之前完成。 -`await` 表达式只能在异步的上下文中出现,比如传入 `async(priority:operation:)` 函数的尾随闭包中。它不能在`defer` 语句的闭包中,或者在同步函数的自动闭包中出现。 + `await` 表达式返回值就是该*表达式*的值。 + +被 `await` 标记的表达式被称为*潜在的暂停点*。 + +异步函数的执行可以在每个标记 `await` 的表达式的位置暂停。除此之外,并发代码的执行永远不会在其他位置暂停。这意味着在潜在暂停点之间的代码可以暂时打破不变量的状态进行安全更新,只要更新在下一个潜在暂停点之前完成。 + +await 表达式只能在异步的上下文中出现,比如传入 `async(priority:operation:)` 函数的尾随闭包中。它不能在 `defer` 语句的闭包中,或者在同步函数的自动闭包中出现。 在中缀运算符左侧的表达式被标记上 `await` 运算符时,这个运算符对整个中缀表达式都产生作用。也就是说,你可以使用括号来明确运算符的作用范围。 + + ```swift // await 对两个函数调用都产生作用 sum = await someAsyncFunction() + anotherAsyncFunction() @@ -112,11 +120,13 @@ sum = await (someAsyncFunction() + anotherAsyncFunction()) // 错误:await 只对第一个函数调用产生作用 sum = (await someAsyncFunction()) + anotherAsyncFunction() ``` -`await`表达式不能出现在中缀运算符的的右侧,除非中缀运算符是赋值运算符或者`await` 表达式是被圆括号括起来的。 + +`await` 表达式不能出现在中缀运算符的的右侧,除非中缀运算符是赋值运算符或者 `await` 表达式是被圆括号括起来的。 如果表达式中同时包含 `try` 和 `await` 运算符,`try` 运算符必须在前面。 -> Await 表达式语法: + +> Await 表达式语法: > > *await运算符* → **`await`** @@ -125,64 +135,64 @@ sum = (await someAsyncFunction()) + anotherAsyncFunction() *中缀表达式*由中缀运算符和左右参数表达式组成。形式如下: ```swift -<#左侧参数#> <#中缀运算符#> <#右侧参数#> +<#left-左侧参数#> <#中缀运算符#> <#右侧参数t#> ``` -关于这些运算符的更多信息,请参阅 . +关于这些运算符的更多信息,请参阅. -关于 Swift 标准库提供的运算符的更多信息,请参阅 [Operator Declarations](https://developer.apple.com/documentation/swift/operator_declarations). +关于 Swift 标准库提供的运算符的更多信息,请参阅[Operator Declarations](https://developer.apple.com/documentation/swift/operator_declarations). -> 注意:在解析时,一个中缀表达式将作为一个扁平列表表示,然后根据运算符的优先级,再进一步进行组合。例如,`2 + 3 * 5` 首先被看作具有五个元素的列表,即 `2`、`+`、`3`、`*`、`5`,随后根据运算符优先级组合为 `(2 + (3 * 5))`。 +> 注意 +> 在解析时,一个中缀表达式将作为一个扁平列表表示,然后根据运算符的优先级,再进一步进行组合。例如,> `2 + 3 * 5` 首先被看作具有五个元素的列表,即 `2`、`+`、`3`、`*`、`5`,随后根据运算符优先级组合为 `(2 + > (3 * 5))`。 -> 中置表达式语法 +> Grammar of an infix expression: > -> *中置表达式 * → *中置运算符* *前缀表达式* \ -> *中置表达式 * → *赋值运算符* *try 运算符*_?_ *await运算符*_?_ *前缀表达式* \ -> *中置表达式 * → *条件运算符* *条件运算符 try运算符*_?_ *await运算符*_?_ * 前缀表达式* \ -> *中置表达式 * → *类型转换运算符* \ -> *中置表达式 * → *中置表达式* *中置表达式列表*_?_ +> *infix-expression* → *infix-operator* *prefix-expression* \ +> *infix-expression* → *assignment-operator* *try-operator*_?_ *await-operator*_?_ *prefix-expression* \ +> *infix-expression* → *conditional-operator* *try-operator*_?_ *await-operator*_?_ *prefix-expression* \ +> *infix-expression* → *type-casting-operator* \ +> *infix-expressions* → *infix-expression* *infix-expressions*_?_ -### 赋值运算符 +### 赋值表达式 -*赋值表达式*会为某个给定的表达式赋值,形式如下; +赋值表达式会为某个给定的表达式赋值,形式如下; ```swift -<#表达#> = <#值#> +<#表达式#> = <#值#> ``` 右边的值会被赋值给左边的表达式。如果左边表达式是一个元组,那么右边必须是一个具有同样元素个数的元组。(嵌套元组也是允许的。)右边的值中的每一部分都会被赋值给左边的表达式中的相应部分。例如: ```swift (a, _, (b, c)) = ("test", 9.45, (12, 3)) -// a 为 "test",b 为 12,c 为 3,9.45 会被忽略 +// a 为 "test",b 为 12,c 为 3,9.45 会被忽略 ``` + 赋值运算符不返回任何值。 -> 赋值运算符语法 +> Grammar of an assignment operator: > -> *赋值运算符* → **`=`** +> *assignment-operator* → **`=`** ### 三元条件运算符 *三元条件运算符*会根据条件来对两个给定表达式中的一个进行求值,形式如下: ```swift -<#条件#> ? <#表达式(条件为真则使用)#> : <#表达式(条件为假则使用) #> +<#条件#> ? <#表达式 (条件为真则使用)#> : <#表达式(条件为假则使用)#> ``` 如果条件为真,那么对第一个表达式进行求值并返回结果。否则,对第二个表达式进行求值并返回结果。未使用的表达式不会进行求值。 -关于使用三元条件运算符的例子,请参阅: . +关于使用三元条件运算符的例子,请参阅 . -> 三元条件运算符语法 +> Grammar of a conditional operator: > -> *三元条件运算符* → **`?`** *表达* **`:`** - -### 类型转换运算符 +> *conditional-operator* → **`?`** *expression* **`:`** -有四种类型转换运算符: `is`运算符、`as`运算符、`as?`运算符和`as!`操作员。 +### 类型转换运算符 -它们具有以下形式: +有 4 种类型转换运算符:is、as、as? 和 as!。它们有如下的形式: ```swift <#表达式#> is <#类型#> @@ -191,7 +201,7 @@ sum = (await someAsyncFunction()) + anotherAsyncFunction() <#表达式#> as! <#类型#> ``` -`is` 运算符在运行时检查表达式能否向下转化为指定的类型,如果可以则返回 `ture`,否则返回 `false`。 +`is` 运算符在运行时检查表达式能否向下转化为指定的类型,如果可以则返回 `ture`,否则返回 false。 `as` 运算符在编译时执行向上转换和桥接。向上转换可将表达式转换成父类的实例而无需使用任何中间变量。以下表达式是等价的: @@ -210,26 +220,27 @@ f(x as Any) // 打印 "Function for Any" ``` -桥接可将 Swift 标准库中的类型(例如 `String`)作为一个与之相关的 Foundation 类型(例如 `NSString`)来使用,而不需要新建一个实例。关于桥接的更多信息,请参阅 [Working with Foundation Types](https://developer.apple.com/documentation/swift/imported_c_and_objective_c_apis/working_with_foundation_types). +桥接可将 Swift 标准库中的类型(例如 `String`)作为一个与之相关的 Foundation 类型(例如 `NSString`)来使用,而不需要新建一个实例。关于桥接的更多信息,请参阅[Working with Foundation Types](https://developer.apple.com/documentation/swift/imported_c_and_objective_c_apis/working_with_foundation_types). -`as?` 运算符有条件地执行类型转换,返回目标类型的可选值。在运行时,如果转换成功,返回的可选值将包含转换后的值,否则返回 nil。如果在编译时就能确定转换一定会成功或是失败,则会导致编译报错。 +`as?` 运算符有条件地执行类型转换,返回目标类型的可选值。在运行时,如果转换成功,返回的可选值将包含转换后的值,否则返回 `nil`。如果在编译时就能确定转换一定会成功或是失败,则会导致编译报错。 -as! 运算符执行强制类型转换,返回目标类型的非可选值。如果转换失败,则会导致运行时错误。表达式 `x as! T` 效果等同于 `(x as? T)!`。 +`as!` 运算符执行强制类型转换,返回目标类型的非可选值。如果转换失败,则会导致运行时错误。表达式 `x as! T` 效果等同于 `(x as? T)!`。 -关于类型转换的更多内容和例子,请参阅. +关于类型转换的更多内容和例子,请参阅 . +要查看使用类型转换运算符的示例,请参阅 . -> 类型转换运算符的语法: +> Grammar of a type-casting operator: > -> *类型转换运算符* → **`is`** *类型* \ -> *类型转换运算符* → **`as`** *类型* \ -> *类型转换运算符* → **`as`** **`?`** *类型* \ -> *类型转换运算符* → **`as`** **`!`** *类型* +> *type-casting-operator* → **`is`** *type* \ +> *type-casting-operator* → **`as`** *type* \ +> *type-casting-operator* → **`as`** **`?`** *type* \ +> *type-casting-operator* → **`as`** **`!`** *type* ## 基本表达式 -*基本表达式*是最基本的表达式。它们可以单独使用,也可以跟前缀表达式、中置表达式、后缀表达式组合使用。 +*基本表达式是最基本的表达式。它们可以单独使用,也可以跟前缀表达式、中置表达式、后缀表达式组合使用。 -> 基本表达式的语法: +> Grammar of a primary expression: > > *primary-expression* → *identifier* *generic-argument-clause*_?_ \ > *primary-expression* → *literal-expression* \ @@ -246,12 +257,11 @@ as! 运算符执行强制类型转换,返回目标类型的非可选值。如 > *primary-expression* → *selector-expression* \ > *primary-expression* → *key-path-string-expression* - ### 字面量表达式 -*字面量表达式*可由普通字面量(例如字符串或者数字),字典或者数组字面量,或者下面列表中的特殊字面量组成: +字面量表达式可由普通字面量(例如字符串或者数字),字典或者数组字面量,或者下面列表中的特殊字面量组成: -> Note: +> 注意: > Prior to Swift 5.9, > the following special literals were recognized: > `#column`, @@ -270,18 +280,18 @@ as! 运算符执行强制类型转换,返回目标类型的非可选值。如 > [`function()`](https://developer.apple.com/documentation/swift/function()), > and [`line()`](https://developer.apple.com/documentation/swift/line()). - 数组字面量是值的有序集合,形式如下: ```swift [<#值 1#>, <#值 2#>, <#...#>] ``` -数组中的最后一个表达式可以紧跟一个逗号。数组字面量的类型是 `[T]`,这个 `T` 就是数组中元素的类型。如果数组中包含多种类型,`T` 则是跟这些类型最近的的公共父类型。空数组字面量由一组方括号定义,可用来创建特定类型的空数组。 +数组中的最后一个表达式可以紧跟一个逗号。数组字面量的类型是 `[T]`,这个 `T` 就是数组中元素的类型。如果数组中包含多种类型,`T` 则是跟这些类型最近的的公共父类型。空数组字面量由一组方括号定义,可用来创建特定类型的空数组。 ```swift var emptyArray: [Double] = [] ``` + 字典字面量是一个包含无序键值对的集合,形式如下: ```swift @@ -296,14 +306,15 @@ var emptyDictionary: [String: Double] = [:] Xcode 使用 playground 字面量对程序编辑器中的颜色、文件或者图片创建可交互的展示。在 Xcode 之外的空白文本中,playground 字面量使用一种特殊的字面量语法来展示。 -更多关于在 Xcode 中使用 playground 字面量的信息,请参阅 [Add a color, file, or image literal](https://help.apple.com/xcode/mac/current/#/dev4c60242fc) +更多关于在 Xcode 中使用 playground 字面量的信息,请参阅[Add a color, file, or image literal](https://help.apple.com/xcode/mac/current/#/dev4c60242fc) +in Xcode Help. -> 字面量表达式语法: +> Grammar of a literal expression: > -> *字面量表达式* → *字面量* \ -> *字面量表达式* → *数组字面量* | *字典字面量* | *练习场字面量* +> *literal-expression* → *literal* \ +> *literal-expression* → *array-literal* | *dictionary-literal* | *playground-literal* > -> *字面量表达式* → **`[`** *array-literal-items*_?_ **`]`** \ +> *array-literal* → **`[`** *array-literal-items*_?_ **`]`** \ > *array-literal-items* → *array-literal-item* **`,`**_?_ | *array-literal-item* **`,`** *array-literal-items* \ > *array-literal-item* → *expression* > @@ -317,14 +328,14 @@ Xcode 使用 playground 字面量对程序编辑器中的颜色、文件或者 ### Self 表达式 -`self`表达式是对当前类型或者当前实例的显式引用,它有如下形式: + `self` 表达式是对当前类型或者当前实例的显式引用,它有如下形式: ```swift self self.<#成员名称#> self[<#下标索引#>] -self(<#构造器参数#>) -self.init(<#构造器参数#>) +self(<#初始化器参数#>) +self.init(<#初始化器参数#>) ``` 如果在构造器、下标、实例方法中,`self` 引用的是当前类型的实例。在一个类型方法中,`self` 引用的是当前的类型。 @@ -339,6 +350,7 @@ class SomeClass { } } ``` + 在 `mutating` 方法中,你可以对 `self` 重新赋值: ```swift @@ -350,13 +362,13 @@ struct Point { } ``` -> Self 表达式语法: +> Grammar of a self expression: > -> *self表达式* → **`self`** | *self表达式* | *self下标表达式* | *self构造表达式* +> *self-expression* → **`self`** | *self-method-expression* | *self-subscript-expression* | *self-initializer-expression* > -> *self方法表达式* → **`self`** **`.`** *.标识符* \ -> *self下标表达式* → **`self`** **`[`** *函数调用参数表* **`]`** \ -> *self构造器表达式* → **`self`** **`.`** **`init`** +> *self-method-expression* → **`self`** **`.`** *identifier* \ +> *self-subscript-expression* → **`self`** **`[`** *function-call-argument-list* **`]`** \ +> *self-initializer-expression* → **`self`** **`.`** **`init`** ### 父类表达式 @@ -365,24 +377,24 @@ struct Point { ```swift super.<#成员名称#> super[<#下标索引#>] -super.init(<#构造器参数#>) +super.init(<#初始化器参数#>) ``` 第一种形式用来访问父类的某个成员,第二种形式用来访问父类的下标,第三种形式用来访问父类的构造器。 子类可以通过父类表达式在它们的成员、下标和构造器中使用父类中的实现。 -> 父类表达式语法: +> Grammar of a superclass expression: > -> *父类表达式* → *父类方法表达式* | *父类下标表达式* | *父类构造器表达式* +> *superclass-expression* → *superclass-method-expression* | *superclass-subscript-expression* | *superclass-initializer-expression* > -> *父类方法表达式* → **`super`** **`.`** *标识符* \ -> *父类下标表达式* → **`super`** **`[`** *函数调用参数表* **`]`** \ -> *父类构造器表达式* → **`super`** **`.`** **`init`** +> *superclass-method-expression* → **`super`** **`.`** *identifier* \ +> *superclass-subscript-expression* → **`super`** **`[`** *function-call-argument-list* **`]`** \ +> *superclass-initializer-expression* → **`super`** **`.`** **`init`** -### 条件表达式 +### 闭包表达式 -*条件表达式*根据条件值计算为多个给定值之一。它具有以下形式之一: +*闭包表达式*会创建一个闭包,在其他语言中也叫 *lambda* 或匿名函数。跟函数一样,闭包包含了待执行的代码,不同的是闭包还会捕获所在环境中的常量和变量。它的形式如下: ```swift if <#condition 1#> { @@ -403,32 +415,34 @@ default: } ``` -除了以下段落描述的差异之外,条件表达式与`if`语句或`switch`语句具有相同的行为和语法。 +如果闭包的主体中含有 try 表达式,则认为该闭包会引发异常。同理,若闭包主体含有 await 表达式,则认为该闭包是异步的。 + +闭包还有几种特殊的形式,能让闭包使用起来更加简洁: -条件表达式仅出现在以下上下文中: + - 作为变量赋值的值。 + - 作为变量或常量声明的初始值。 + - 作为 `throw` 表达式引发的错误。 + - 作为函数、闭包或属性 getter 的返回值。 + - 作为条件表达式分支中的值。 -- 作为分配给变量的值。 -- 作为变量或常量声明中的初始值。 -- 作为由 `throw `表达式引发的错​​误。 -- 作为函数、闭包或属性 `getter` 返回的值。 -- 作为条件表达式分支内的值。 +条件表达式的分支是穷尽的,确保表达式总是会返回一个值,无论条件如何。这意味着每个 `if` 分支都需要一个对应的 `else` 分支。 -条件表达式的分支是详尽的,确保无论条件如何,表达式始终生成一个值。这意味着每个if分支都需要一个相应的else分支。 +无论条件如何,这意味着每个 `if` 分支都需要一个对应的 `else` 分支。 -每个分支包含一个表达式(当该分支的条件为 true 时用作条件表达式的值)、一个 `throw`语句或对永不返回的函数的调用。 +每个分支包含一个单独的表达式,该表达式在该分支的条件为真时用作条件表达式的值,或者是一个 `throw` 语句,或是一个永不返回的函数调用。 -每个分支必须产生相同类型的值。由于每个分支的类型检查是独立的,因此有时需要显式指定值的类型,例如当分支包含不同类型的文字时,或者当分支的值为`nil`时。当您需要提供此信息时,请向结果分配到的变量添加类型注释,或向分支的值添加`as`强制转换。 +每个分支必须产生相同类型的值。由于每个分支的类型检查是独立的,有时你需要明确指定值的类型,例如当分支包含不同类型的字面量,或者当某个分支的值为 `nil` 时。当你需要提供这些信息时,可以在结果赋值的变量上添加类型注解,或者在分支值上添加 `as` 类型转换。 ```swift let number: Double = if someCondition { 10 } else { 12.34 } let number = if someCondition { 10 as Double } else { 12.34 } ``` -在结果生成器中,条件表达式只能显示为变量或常量的初始值。此行为意味着当您在结果生成器中编写`if`或`switch` 时(在变量或常量声明之外),该代码将被理解为分支语句,并且结果生成器的方法之一会转换该代码。 +在结果构建器内,条件表达式只能作为变量或常量的初始值出现。这种行为意味着,当你在结果构建器中编写 `if` 或 `switch` —— 在变量或常量声明之外 —— 这段代码被理解为分支语句,并且结果构建器的一个方法会对这段代码进行转换。 -不要将条件表达式放入try表达式中,即使条件表达式的分支之一抛出异常。 +即使条件表达式的某个分支会抛出异常,也不要将条件表达式放入 try 表达式中。 -> 条件句语法: +> Grammar of a conditional expression: > > *conditional-expression* → *if-expression* | *switch-expression* > @@ -443,7 +457,7 @@ let number = if someCondition { 10 as Double } else { 12.34 } ### 闭包表达式 -闭包表达式会创建一个闭包,在其他语言中也叫 *lambda* 或匿名函数。跟函数一样,闭包包含了待执行的代码,不同的是闭包还会捕获所在环境中的常量和变量。它的形式如下: +*闭包表达式*会创建一个闭包,在其他语言中也叫 *lambda* 或匿名函数。跟函数一样,闭包包含了待执行的代码,不同的是闭包还会捕获所在环境中的常量和变量。它的形式如下: ```swift { (<#parameters#>) -> <#return type#> in @@ -451,7 +465,7 @@ let number = if someCondition { 10 as Double } else { 12.34 } } ``` -闭包的参数声明形式跟函数一样,请参阅。 +闭包的参数声明形式跟函数一样,请参阅 . 在闭包表达式中写入 `throws` 或 `async` 将显式地将闭包标记为丢掷或异步的。 @@ -491,11 +505,11 @@ myFunction { $0 + $1 } 使用闭包表达式时,可以不必将其存储在一个变量或常量中,例如作为函数调用的一部分来立即使用一个闭包。在上面的例子中,传入 `myFunction` 的闭包表达式就是这种立即使用类型的闭包。因此,一个闭包是否逃逸与其使用时的上下文相关。一个会被立即调用或者作为函数的非逃逸参数传递的闭包表达式是非逃逸的,否则,这个闭包表达式是逃逸的。 -关于逃逸闭包的内容,请参阅:. +关于逃逸闭包的内容,请参阅. #### 捕获列表 -默认情况下,闭包表达式从其周围范围捕获常量和变量,并使用强引用指向它们。你可以通过一个捕获列表来显式指定它的捕获行为。 +默认情况下,闭包会捕获附近作用域中的常量和变量,并使用强引用指向它们。你可以通过一个*捕获列表*来显式指定它的捕获行为。 捕获列表在参数列表之前,由中括号括起来,里面是由逗号分隔的一系列表达式。一旦使用了捕获列表,就必须使用 `in` 关键字,即使省略了参数名、参数类型和返回类型。 @@ -531,34 +545,38 @@ let closure = { [x] in x.value = 10 y.value = 10 closure() -// Prints "10 10" +// 打印 "10 10" ``` + 如果捕获列表中的值是类类型,你可以使用 `weak` 或者 `unowned` 来修饰它,闭包会分别用弱引用和无主引用来捕获该值。 ```swift -myFunction { print(self.title) } // 隐式强引用捕获 -myFunction { [self] in print(self.title) } // 显式强引用捕获 -myFunction { [weak self] in print(self!.title) } // 弱引用捕获 -myFunction { [unowned self] in print(self.title) } // 无主引用捕获 +myFunction { print(self.title) } // implicit strong capture +myFunction { [self] in print(self.title) } // explicit strong capture +myFunction { [weak self] in print(self!.title) } // weak capture +myFunction { [unowned self] in print(self.title) } // unowned capture ``` + 在捕获列表中,也可以将任意表达式的值绑定到一个常量上。该表达式会在闭包被创建时进行求值,闭包会按照指定的引用类型来捕获表达式的值。例如: ```swift // 以弱引用捕获 self.parent 并赋值给 parent myFunction { [weak parent = self.parent] in print(parent!.title) } ``` + 关于闭包表达式的更多信息和例子,请参阅 . + 关于捕获列表的更多信息和例子,请参阅 . -> 闭包表达式语法 +> Grammar of a closure expression: > -> *闭包表达式* → **`{`** *特性*_?_ *闭包签名*_?_ *语句*_?_ **`}`** +> *closure-expression* → **`{`** *attributes*_?_ *closure-signature*_?_ *statements*_?_ **`}`** > -> *闭包签名* → *捕获列表*_?_ *闭包形参子句* **`async`**_?_ *throws*_?_ *函数结果*_?_ **`in`** \ -> *闭包签名 * → *捕获列表* **`in`** +> *closure-signature* → *capture-list*_?_ *closure-parameter-clause* **`async`**_?_ *throws-clause*_?_ *function-result*_?_ **`in`** \ +> *closure-signature* → *capture-list* **`in`** > -> *闭包形参子句* → **`(`** **`)`** | **`(`** *闭包形参列表* **`)`** | *标识符列表* \ -> *闭包形参列表* → *闭包形参* | *闭包形参* **`,`** *闭包形参列表* \ +> *closure-parameter-clause* → **`(`** **`)`** | **`(`** *closure-parameter-list* **`)`** | *identifier-list* \ +> *closure-parameter-list* → *closure-parameter* | *closure-parameter* **`,`** *closure-parameter-list* \ > *closure-parameter* → *closure-parameter-name* *type-annotation*_?_ \ > *closure-parameter* → *closure-parameter-name* *type-annotation* **`...`** \ > *closure-parameter-name* → *identifier* @@ -572,18 +590,19 @@ myFunction { [weak parent = self.parent] in print(parent!.title) } ### 隐式成员表达式 -若类型可被推断出来,可以使用*隐式成员表达式*来访问某个类型的成员(例如某个枚举成员或某个类型方法),形式如下: +*若类型*可被推断出来,可以使用*隐式成员表达式*来访问某个类型的成员(例如某个枚举成员或某个类型方法),形式如下: ```swift .<#成员名称#> ``` -例如: +例如: ```swift var x = MyEnumeration.someValue x = .anotherValue ``` + 如果推断的是可选类型,可以在隐式成员表达式里使用不可选类型的成员。 ```swift @@ -609,22 +628,22 @@ let z: SomeClass = .sharedSubclass ``` 上面的代码中,`x` 的类型和上下文的隐式类型完全匹配,`y` 的类型是从 `SomeClass` 转换成 `SomeClass?`,`z` 的类型是从 `SomeSubclass` 转换成 `SomeClass`。 -> 隐式成员表达式语法 +> Grammar of an implicit member expression: > > *implicit-member-expression* → **`.`** *identifier* \ > *implicit-member-expression* → **`.`** *identifier* **`.`** *postfix-expression* ### 圆括号表达式 -*圆括号表达式*是由圆括号包围的表达式。你可以用圆括号说明成组的表达式的先后操作。成组的圆括号不会改变表达式的类型 - 例如 `(1)` 的类型就是简单的 `Int`。 +圆括号表达式是由圆括号包围的表达式。你可以用圆括号说明成组的表达式的先后操作。成组的圆括号不会改变表达式的类型 - 例如 `(1)` 的类型就是简单的 `Int`。 -> 圆括号表达式语法 +> Grammar of a parenthesized expression: > -> *圆括号表达式* → **`(`** *表达式* **`)`** +> *parenthesized-expression* → **`(`** *expression* **`)`** ### 元组表达式 -*元组表达式*由圆括号和其中多个逗号分隔的子表达式组成。每个子表达式前面可以有一个标识符,用冒号隔开。元组表达式形式如下: +元组表达式由圆括号和其中多个逗号分隔的子表达式组成。每个子表达式前面可以有一个标识符,用冒号隔开。元组表达式形式如下: ```swift (<#标识符 1#>: <#表达式 1#>, <#标识符 2#>: <#表达式 2#>, <#...#>) @@ -634,9 +653,14 @@ let z: SomeClass = .sharedSubclass 元组表达式可以一个表达式都没有,也可以包含两个或是更多的表达式。单个表达式用括号括起来就是括号表达式了。 -> 注意:在 Swift 中,空的元组表达式和空的元组类型都写作 `()`。由于 `Void` 是 `()` 的类型别名,因此可以使用它来表示空的元组类型。虽然如此,`Void` 就像所有的类型别名一样,永远是一个类型——不能表示空的元组表达式。 +> Note: Both an empty tuple expression and an empty tuple type +> are written `()` in Swift. +> Because `Void` is a type alias for `()`, +> you can use it to write an empty tuple type. +> However, like all type aliases, `Void` is always a type --- +> you can't use it to write an empty tuple expression. -> 元组表达式语法 +> Grammar of a tuple expression: > > *tuple-expression* → **`(`** **`)`** | **`(`** *tuple-element* **`,`** *tuple-element-list* **`)`** \ > *tuple-element-list* → *tuple-element* | *tuple-element* **`,`** *tuple-element-list* \ @@ -644,78 +668,72 @@ let z: SomeClass = .sharedSubclass ### 通配符表达式 -*通配符表达式*可以在赋值过程中显式忽略某个值。例如下面的代码中,10 被赋值给 x,而 20 则被忽略: - - +*通配符表达式*可以在赋值过程中显式忽略某个值。例如下面的代码中,`10` 被赋值给 `x`,而 `20` 则被忽略: ```swift (x, _) = (10, 20) -// x 为 10,20 被忽略 +// x 为 10,20 被忽略 ``` -> 通配符表达式语法 + +> Grammar of a wildcard expression: > -> *通配符表达式* → **`_`** +> *wildcard-expression* → **`_`** -### 宏表达式 +### 宏扩展表达式 -Key-path 表达式引用一个类型的属性或下标。在动态语言中使场景可以使用 Key-path 表达式,例如观察键值对。格式为: +*宏扩展表达式*由一个宏名称和一个用逗号分隔的宏参数列表(在括号内)组成。宏在编译时被扩展。宏扩展表达式的形式如下: ```swift <#macro name#>(<#macro argument 1#>, <#macro argument 2#>) ``` -宏扩展表达式不能作为参数的默认值出现,除了 Swift 标准库中的 `file()` 和 `line()` 宏。当用作函数或方法参数的默认值时,这些宏将使用调用站点的源代码位置(而不是它们在函数定义中出现的位置)进行计算。 +如果宏不接受任何参数,宏扩展表达式可以省略宏名称后面的括号。 + +宏扩展表达式不能作为参数的默认值,除了 Swift 标准库中的 [`file()`][] 和 [`line()`][] 宏。当这些宏作为函数或方法参数的默认值时,它们会使用调用位置的源代码位置进行评估,而不是在函数定义中出现的位置。 [`file()`]: https://developer.apple.com/documentation/swift/file() [`line()`]: https://developer.apple.com/documentation/swift/line() -您可以使用宏表达式来调用独立宏。要调用附加的宏,请使用 中描述的自定义属性语法。独立宏和附加宏都扩展如下: - +你使用宏表达式来调用独立宏。要调用附加宏,请使用在 . +中描述的自定义属性语法。独立宏和附加宏的扩展方式如下: 1. Swift 解析源代码以生成抽象语法树(AST)。 -2. 宏实现接收 AST 节点作为其输入并执行该宏所需的转换。 +2. 宏实现接收 AST 节点作为输入,并执行该宏所需的转换。 -3. 宏实现生成的转换后的 AST 节点将添加到原始 AST 中。 +3. 宏实现生成的转换后 AST 节点会被添加到原始 AST 中。 -每个宏的扩展都是独立且自成体系的。但是,作为性能优化,Swift 可能会启动一个实现宏的外部进程,并重用同一进程来扩展多个宏。当您实现宏时,该代码不得依赖于您的代码之前扩展的宏,或任何其他外部状态(例如当前时间)。 +每个宏的扩展是独立且自包含的。然而,为了优化性能,Swift 可能会启动一个外部进程来实现宏,并重用同一个进程来扩展多个宏。当你实现一个宏时,该代码不能依赖于你的代码之前扩展过的宏,也不能依赖于任何其他外部状态,例如当前时间。 -对于具有多个角色的嵌套宏和附加宏,会重复展开过程。嵌套宏展开表达式从外向内展开。例如,在下面的代码中, `outerMacro(_:) `首先展开,未展开的对`innerMacro(_:)`调用出现在 `outerMacro(_:)`接收的抽象语法树中。输入 +对于嵌套宏和具有多个角色的附加宏,扩展过程会重复。嵌套的宏扩展表达式是从外到内进行扩展的。例如,在下面的代码中,`outerMacro(_:)` 首先被扩展,未扩展的对 `innerMacro(_:)` 的调用出现在 `outerMacro(_:)` 作为输入接收的抽象语法树中。 ```swift #outerMacro(12, #innerMacro(34), "some text") ``` -具有多个角色的附加宏将为每个角色扩展一次。每个扩展都接收相同的原始 AST 作为其输入。 Swift 通过收集所有生成的 AST 节点并将它们放在 AST 中相应的位置来形成整体扩展。 +一个具有多个角色的附加宏会针对每个角色进行一次扩展。每次扩展都接收相同的原始 AST 作为输入。Swift 通过收集所有生成的 AST 节点,并将它们放入 AST 中相应的位置,形成整体扩展。 -有关 Swift 中宏的概述,请参阅 . +有关 Swift 中宏的概述 请参阅 。 -> 宏展开表达式的语法: +> Grammar of a macro-expansion expression: > > *macro-expansion-expression* → **`#`** *identifier* *generic-argument-clause*_?_ *function-call-argument-clause*_?_ *trailing-closures*_?_ -### 键路径表达式 +### Key-Path 表达式 -*键路径表达式*指的是类型的属性或下标。您可以在动态编程任务中使用键路径表达式,例如键值观察。它们具有以下形式: +Key-path 表达式引用一个类型的属性或下标。在动态语言中使场景可以使用 Key-path 表达式,例如观察键值对。格式为: ```swift -\<#type name#>.<#path#> +\<#类型名#>.<#路径#> ``` -*类型名称*是具体类型的名称,包括任何泛型参数,例如 `String` 、 `[Int]` 或 `Set` 。 - -该*路径*由属性名称、下标、可选链表达式和强制展开表达式组成。这些关键路径组件中的每一个都可以根据需要以任何顺序重复多次。 +*类型名*是一个具体类型的名称,包含任何泛型参数,例如 `String`、`[Int]` 或 `Set`。 -在编译时,键路径表达式被[`KeyPath`](https://developer.apple.com/documentation/swift/keypath) 类的实例替换。 +*路径*可由属性名称、下标、可选链表达式或者强制解包表达式组成。以上任意 key-path 组件可以以任何顺序重复多次。 -要使用键路径访问值,请将键路径传递给 `subscript(keyPath:)` 下标,该下标适用于所有类型。例如: +在编译期,key-path 表达式会被一个 [`KeyPath`](https://developer.apple.com/documentation/swift/keypath) 类的实例替换。 - +对于所有类型,都可以通过传递 key-path 参数到下标方法 `subscript(keyPath:)` 来访问它的值。例如: ```swift struct SomeStructure { @@ -726,27 +744,10 @@ let s = SomeStructure(someValue: 12) let pathToProperty = \SomeStructure.someValue let value = s[keyPath: pathToProperty] -// value is 12 +// 值为 12 ``` - - -在类型推断可以确定隐含类型的上下文中,可以省略类型名称。以下代码使用 `\.someProperty` 而不是 `\SomeClass.someProperty` : +在一些可以通过类型推断来确定所访问的具体类型的上下文中,可以省略 key-path 前的类型名字。下面的代码使用 `\.someProperty` 代替了 `SomeClass.someProperty` : ```swift class SomeClass: NSObject { @@ -762,7 +763,7 @@ c.observe(\.someProperty) { object, change in } ``` -该*路径* 可以引用self来创建身份密钥路径 `( \.self )`。身份键路径引用整个实例,因此您可以使用它一步来访问和更改存储在变量中的所有数据。例如: +使用 `self` 作为路径可以创建一个恒等 key path (`\.self`)。恒等 key path 可以作为整个实例的引用,因此你仅需一步操作便可以利用它来访问以及修改其存储的所有数据。例如: ```swift var compoundValue = (a: 1, b: 2) @@ -770,7 +771,7 @@ var compoundValue = (a: 1, b: 2) compoundValue[keyPath: \.self] = (a: 10, b: 20) ``` -该路径可以包含多个属性名称,以句点分隔,以引用属性值的属性。此代码使用关键路径表达式 `\OuterStructure.outer.someValue` 访问 `OuterStructure` 类型的 `outer` 属性的 `someValue` 属性: +通过点语法,可以让路径包含多个属性名称,以此来访问某实例的属性的属性。下面的代码使用 key-path 表达式 `\OuterStructure.outer.someValue` 来访问 `OuterStructure` 类型中 `outer` 属性的 `someValue` 属性。 ```swift struct OuterStructure { @@ -787,14 +788,15 @@ let nestedValue = nested[keyPath: nestedKeyPath] // nestedValue is 24 ``` -*路径*可以包含使用括号的下标,只要下标的参数类型符合 `Hashable` 协议即可。此示例使用键路径中的下标来访问数组的第二个元素: +路径中也可以包含使用中括号的下标访问,只要下标访问的参数类型满足 `Hashable` 协议即可。下面的例子在 key path 中使用了下标来访问数组的第二个元素。 ```swift let greetings = ["hello", "hola", "bonjour", "안녕"] let myGreeting = greetings[keyPath: \[String].[1]] // myGreeting is 'hola' ``` -下标中使用的值可以是命名值或文字。使用值语义在关键路径中捕获值。以下代码在键路径表达式和闭包中使用变量 `index` 来访问 `greetings` 数组的第三个元素。当 `index` 被修改时,键路径表达式仍然引用第三个元素,而闭包使用新索引。 + +T下标访问中使用的值可以是一个变量或者字面量,并且 key-path 表达式会使用值语义来捕获此值。下面的代码在 key-path 表达式和闭包中都使用了 `index` 变量来访问 `greetings` 数组的第三个元素。当 `index` 被修改时,key-path 表达式仍旧引用数组第三个元素,而闭包则使用了新的索引值。 ```swift var index = 2 @@ -802,20 +804,21 @@ let path = \[String].[index] let fn: ([String]) -> String = { strings in strings[index] } print(greetings[keyPath: path]) -// Prints "bonjour" +// 打印 "bonjour" print(fn(greetings)) -// Prints "bonjour" +// 打印 "bonjour" -// Setting 'index' to a new value doesn't affect 'path' +// 将 'index' 设置为一个新的值不会影响到 'path' index += 1 print(greetings[keyPath: path]) -// Prints "bonjour" +// 打印 "bonjour" -// Because 'fn' closes over 'index', it uses the new value +// 'fn' 闭包使用了新值。 print(fn(greetings)) -// Prints "안녕" +// 打印 "안녕" ``` -该路径可以使用可选链接和强制展开。此代码在键路径中使用可选链接来访问可选字符串的属性: + +路径可以使用可选链和强制解包。下面的代码在 key path 中使用了可选链来访问可选字符串的属性。 ```swift let firstGreeting: String? = greetings.first @@ -827,7 +830,8 @@ let count = greetings[keyPath: \[String].first?.count] print(count as Any) // Prints "Optional(5)" ``` -您可以混合和匹配关键路径的组件来访问深度嵌套在类型中的值。以下代码通过使用组合这些组件的键路径表达式来访问数组字典的不同值和属性。 + +可以混合使用各种 key path 组件来访问一些深度嵌套类型的值。下面的代码通过组合不同的组件,使用 key-path 表达式访问了一个字典数组中不同的值和属性。 ```swift let interestingNumbers = ["prime": [2, 3, 5, 7, 11, 13, 17], @@ -842,7 +846,8 @@ print(interestingNumbers[keyPath: \[String: [Int]].["hexagonal"]!.count]) print(interestingNumbers[keyPath: \[String: [Int]].["hexagonal"]!.count.bitWidth]) // Prints "64" ``` -您可以在通常提供函数或闭包的上下文中使用键路径表达式。具体来说,您可以使用根类型为 `SomeType` 且其路径生成 `Value` 类型的值的键路径表达式,而不是 `(SomeType) -> Value` 类型的函数或闭包。 + +你可以在平时提供函数或者闭包的上下文里使用 key path 表达式。特别地,你可以用根类型是 `SomeType` 和路径产生 `Value` 类型值的 key path 表达式来替换类型是 `(SomeType) -> Value` 的函数或者闭包。 ```swift struct Task { @@ -855,11 +860,12 @@ var toDoList = [ Task(description: "Visit Boston in the Fall.", completed: false), ] -// Both approaches below are equivalent. +// 下面两种写法是等价的。 let descriptions = toDoList.filter(\.completed).map(\.description) let descriptions2 = toDoList.filter { $0.completed }.map { $0.description } ``` -关键路径表达式的任何副作用仅在计算表达式的点进行计算。例如,如果您在关键路径表达式的下标内进行函数调用,则该函数仅在计算表达式时调用一次,而不是每次使用关键路径时都被调用。 + +任何 key path 表达式的副作用发生的关键在于表达式在哪里被执行。例如,如果你在 key path 表达式中的一个下标里使用函数调用,该函数只会在表达式计算的时候调用一次,而不是每次这个 key path 被使用的时候。 ```swift func makeIndex() -> Int { @@ -874,11 +880,11 @@ let taskKeyPath = \[Task][makeIndex()] let someTask = toDoList[keyPath: taskKeyPath] ``` -有关在与 Objective-C API 交互的代码中使用关键路径的更多信息,请参阅 [Using Objective-C Runtime Features in Swift](https://developer.apple.com/documentation/swift/using_objective_c_runtime_features_in_swift). -有关键值编码和键值观察的信息,请参阅[Key-Value Coding Programming Guide](https://developer.apple.com/library/content/documentation/Cocoa/Conceptual/KeyValueCoding/index.html#//apple_ref/doc/uid/10000107i) +关于更多如何使用 key path 与 Objective-C APIs 交互的信息,请参阅 [Using Objective-C Runtime Features in Swift](https://developer.apple.com/documentation/swift/using_objective_c_runtime_features_in_swift). +关于更多 key-value 编程和 key-value 观察的信息,请参阅 [Key-Value Coding Programming Guide](https://developer.apple.com/library/content/documentation/Cocoa/Conceptual/KeyValueCoding/index.html#//apple_ref/doc/uid/10000107i) 和 [Key-Value Observing Programming Guide](https://developer.apple.com/library/content/documentation/Cocoa/Conceptual/KeyValueObserving/KeyValueObserving.html#//apple_ref/doc/uid/10000177i). -> 键路径表达式的语法: +> Grammar of a key-path expression: > > *key-path-expression* → **`\`** *type*_?_ **`.`** *key-path-components* \ > *key-path-components* → *key-path-component* | *key-path-component* **`.`** *key-path-components* \ @@ -889,7 +895,7 @@ let someTask = toDoList[keyPath: taskKeyPath] ### 选择器表达式 -选择器表达式允许您访问用于引用 Objective-C 中的方法或属性的 getter 或 setter 的选择器。它具有以下形式: +*选择器表达式*可以让你通过选择器来引用在 Objective-C 中方法(method)和属性(property)的 setter 和 getter 方法。 ```swift #selector(<#method name#>) @@ -897,7 +903,7 @@ let someTask = toDoList[keyPath: taskKeyPath] #selector(setter: <#property name#>) ``` -方法名称和属性名称必须是对 Objective-C 运行时中可用的方法或属性的引用。选择器表达式的值是 `Selector` 类型的实例。例如: +方法名和属性名必须是存在于 Objective-C 运行时中的方法和属性的引用。选择器表达式的返回值是一个 Selector 类型的实例。例如: ```swift class SomeClass: NSObject { @@ -914,29 +920,9 @@ let selectorForMethod = #selector(SomeClass.doSomething(_:)) let selectorForPropertyGetter = #selector(getter: SomeClass.property) ``` - +当为属性的 getter 创建选择器时,属性名可以是变量属性或者常量属性的引用。但是当为属性的 setter 创建选择器时,属性名只可以是对变量属性的引用。 -为属性的 getter 创建选择器时,*属性名称*可以是对变量或常量属性的引用。相反,当为属性的设置器创建选择器时,*属性名称* 必须仅是对变量属性的引用。 - -*方法名称*可以包含用于分组的括号,以及用于消除共享名称但具有不同类型签名的方法之间的歧义的 `as`运算符。例如: +方法名称可以包含圆括号来进行分组,并使用 as 操作符来区分具有相同方法名但类型不同的方法,例如: ```swift extension SomeClass { @@ -946,55 +932,28 @@ extension SomeClass { let anotherSelector = #selector(SomeClass.doSomething(_:) as (SomeClass) -> (String) -> Void) ``` - +由于选择器是在编译时创建的,因此编译器可以检查方法或者属性是否存在,以及是否在运行时暴露给了 Objective-C 。 -因为选择器是在编译时创建的,而不是在运行时创建的,所以编译器可以检查方法或属性是否存在以及它们是否暴露给 Objective-C 运行时。 +> Note: Although the *method name* and the *property name* are expressions, +> they're never evaluated. -> 注意:虽然*方法名称*和*属性名称*是表达式,但它们永远不会被求值 +更多关于如何在 Swift 代码中使用选择器来与 Objective-C API 进行交互的信息,请参阅 [Using Objective-C Runtime Features in Swift](https://developer.apple.com/documentation/swift/using_objective_c_runtime_features_in_swift). -有关在与 Objective-C API 交互的 Swift 代码中使用选择器的更多信息,请参阅[Using Objective-C Runtime Features in Swift](https://developer.apple.com/documentation/swift/using_objective_c_runtime_features_in_swift). - -> 选择器表达式的语法: +> Grammar of a selector expression: > > *selector-expression* → **`#selector`** **`(`** *expression* **`)`** \ > *selector-expression* → **`#selector`** **`(`** **`getter:`** *expression* **`)`** \ > *selector-expression* → **`#selector`** **`(`** **`setter:`** *expression* **`)`** - - -### 键路径字符串表达式 +### Key-Path 字符串表达式 -键路径字符串表达式允许您访问用于引用 Objective-C 中的属性的字符串,以用于键值编码和键值观察 API。它具有以下形式: +key-path 字符串表达式可以访问一个引用 Objective-C 属性的字符串,通常在 key-value 编程和 key-value 观察 APIs 中使用。其格式如下: ```swift #keyPath(<#property name#>) ``` -*属性名称*必须是对 Objective-C 运行时中可用的属性的引用。在编译时,键路径字符串表达式被替换为字符串文字。例如: +属性名必须是一个可以在 Objective-C 运行时使用的属性的引用。在编译期,key-path 字符串表达式会被一个字符串字面量替换。例如: ```swift class SomeClass: NSObject { @@ -1010,32 +969,10 @@ let keyPath = #keyPath(SomeClass.someProperty) if let value = c.value(forKey: keyPath) { print(value) } -// Prints "12" -``` - - - -当您在类中使用键路径字符串表达式时,您可以通过仅编写属性名称而不编写类名称来引用该类的属性。 +// 打印 "12" +``` + +当在一个类中使用 key-path 字符串表达式时,可以省略类名,直接使用属性名来访问这个类的某个属性。 ```swift extension SomeClass { @@ -1044,44 +981,30 @@ extension SomeClass { } } print(keyPath == c.getSomeKeyPath()) -// Prints "true" +// 打印 "true" ``` - +由于 key-path 字符串表达式在编译期才创建,编译期可以检查属性是否存在,以及属性是否暴露给 Objective-C 运行时。 -由于关键路径字符串是在编译时而不是运行时创建的,因此编译器可以检查该属性是否存在以及该属性是否公开给 Objective-C 运行时。 - -有关在与 Objective-C API 交互的 Swift 代码中使用关键路径的更多信息,请参阅[Using Objective-C Runtime Features in Swift](https://developer.apple.com/documentation/swift/using_objective_c_runtime_features_in_swift)。 -有关键值编码和键值观察的信息,请参阅 [Key-Value Coding Programming Guide](https://developer.apple.com/library/content/documentation/Cocoa/Conceptual/KeyValueCoding/index.html#//apple_ref/doc/uid/10000107i) -和 [Key-Value Observing Programming Guide](https://developer.apple.com/library/content/documentation/Cocoa/Conceptual/KeyValueObserving/KeyValueObserving.html#//apple_ref/doc/uid/10000177i)。 +关于更多如何使用 key path 与 Objective-C APIs 交互的信息,请参阅 [Using Objective-C Runtime Features in Swift](https://developer.apple.com/documentation/swift/using_objective_c_runtime_features_in_swift). +关于更多 key-value 编程和 key-value 观察的信息,请参阅 [Key-Value Coding Programming Guide](https://developer.apple.com/library/content/documentation/Cocoa/Conceptual/KeyValueCoding/index.html#//apple_ref/doc/uid/10000107i) +和 [Key-Value Observing Programming Guide](https://developer.apple.com/library/content/documentation/Cocoa/Conceptual/KeyValueObserving/KeyValueObserving.html#//apple_ref/doc/uid/10000177i). -> 注意:虽然*属性名称*是一个表达式,但它永远不会被计算。 +> Note: Although the *property name* is an expression, it's never evaluated. -> 键路径字符串表达式的语法: +> Grammar of a key-path string expression: > -> *键路径字符串表达式* → **`#keyPath`** **`(`** *表达式* **`)`** +> *key-path-string-expression* → **`#keyPath`** **`(`** *expression* **`)`** ## 后缀表达式 -*后缀表达式*是通过对表达式应用后缀运算符或其他后缀语法来形成的。从语法上来说,每个主表达式也是一个后缀表达式。 +*后缀表达式*就是在某个表达式的后面运用后缀运算符或其他后缀语法。从语法构成上来看,基本表达式也是后缀表达式。 -有关这些运算符的行为的信息,请参阅。 +关于这些运算符的更多信息,请参阅 . -有关 Swift 标准库提供的运算符的信息,请参阅[Operator Declarations](https://developer.apple.com/documentation/swift/operator_declarations)。 +关于 Swift 标准库提供的运算符的更多信息,请参阅 [Operator Declarations](https://developer.apple.com/documentation/swift/operator_declarations). -> 后缀表达式的语法: +> Grammar of a postfix expression: > > *postfix-expression* → *primary-expression* \ > *postfix-expression* → *postfix-expression* *postfix-operator* \ @@ -1095,103 +1018,62 @@ print(keyPath == c.getSomeKeyPath()) ### 函数调用表达式 - - -函数调用*表达式*由函数名称和后跟括号中的以逗号分隔的函数参数列表组成。函数调用表达式具有以下形式: +*函数调用表达式*由函数名和在括号里以逗号分隔的参数列表组成。函数调用表达式形式如下: ```swift <#function name#>(<#argument value 1#>, <#argument value 2#>) ``` -*函数名称*可函数名可以是任何其值是函数类型的表达式。 +函数名可以是值为函数类型的任意表达式。 -如果函数定义包含其参数名称,则函数调用必须在其参数值之前包含名称,并用冒号(`:`)分隔。 -这种函数调用表达式具有以下形式: +如果函数声明中指定了形参的名字,那么在调用的时候也必须得写出来,并通过冒号(`:`)分隔。这种函数调用表达式具有以下形式: ```swift <#function name#>(<#argument name 1#>: <#argument value 1#>, <#argument name 2#>: <#argument value 2#>) ``` -函数调用表达式可以在紧跟在右括号之后以闭包表达式的形式包含尾随闭包。尾随闭包被理解为函数的参数,添加在最后一个带括号的参数之后。第一个闭包表达式是无标签的;任何其他闭包表达式前面都有其参数标签。下面的示例显示了使用和不使用尾随闭包语法的函数调用的等效版本: +函数调用表达式可以在函数调用表达式的尾部(右圆括号之后)加上多个尾随闭包,该闭包会作为函数的实参,在括号中最后一个实参后面添加。第一个闭包表达式时没有实参签名的,其他任意闭包表达式签名都有实参标签。如下两种写法是等价的,区别在是否使用尾随闭包语法: ```swift -// someFunction takes an integer and a closure as its arguments +// someFunction 接受整型和闭包的实参 someFunction(x: x, f: { $0 == 13 }) someFunction(x: x) { $0 == 13 } -// anotherFunction takes an integer and two closures as its arguments +// anotherFunction 接受一个整型和两个闭包的实参 anotherFunction(x: x, f: { $0 == 13 }, g: { print(99) }) anotherFunction(x: x) { $0 == 13 } g: { print(99) } ``` - - - - -如果尾随闭包是函数的唯一参数,则可以省略括号。 - -```swift -// someMethod takes a closure as its only argument +如果闭包是该函数的唯一实参,那么圆括号可以省略。 + +```swift +// someMethod 只接受一个闭包参数 myData.someMethod() { $0 == 13 } myData.someMethod { $0 == 13 } ``` -为了在参数中包含尾随闭包,编译器从左到右检查函数的参数,如下所示: +为了支持实参中的尾随闭包,编译器从左到右检查形参列表,如下所示: -| 尾随闭包 | 形参 | 行动 | +| 尾随闭包 | 形参 | 行为 | | ---------------- | --------- | ------ | -| 有标签 | 有标签 | 如果标签相同,闭包和形参匹配,否则跳过该形参| -| 有标签 | 无标记 | 跳过该形参 | -| 无标签 | 有标签或无标签 | 如果形参在结构上类似于下面定义的函数类型,和闭包匹配,否则跳过该形参 | +| 有标签 | 有标签 | 如果标签相同,闭包和形参匹配,否则跳过该形参 | +| 有标签 | 无标签 | 跳过该形参 | +| 无标签 | 有标签或无标签 | 如果形参在结构上类似于下面定义的函数类型,和闭包匹配,否则跳过该形参| -尾随闭包作为其匹配形参的实参传递。在扫描过程被跳过的形参不传递实参——例如,它们使用的是默认形参。当匹配后,扫描会继续下一个尾随闭包和形参。匹配过程结束后,所有的尾随闭包必须有对应的匹配。 +尾随闭包作为其匹配形参的实参传递。 + +在扫描过程被跳过的形参不传递实参——例如,它们使用的是默认形参。当匹配后,扫描会继续下一个尾随闭包和形参。匹配过程结束后,所有的尾随闭包必须有对应的匹配。 如果形参不是输入输出参数,并且类似下面的情况,则算是结构上类似函数类型: -- 类型为函数类型的参数,如`(Bool) -> Int` -- 一个自动闭包参数,其包装表达式的类型是函数类型,例如 `@autoclosure () -> ((Bool) -> Int)` -- 数组元素类型为函数类型的可变参数,例如`((Bool) -> Int)...` -- 其类型被包裹在一层或多层可选中的参数,例如`Optional<(Bool) -> Int>` -- 其类型组合了这些允许类型的参数,例如 `(Optional<(Bool) -> Int>)...` +- 函数类型的形参,例如 `(Bool) -> Int` +- 函数类型表达式的自动闭包形参,例如 `@autoclosure () -> ((Bool) -> Int)` +- 元素是函数类型的可变参数,例如 `((Bool) -> Int)...` +- 单层或多层可选类型的形参,例如 `Optional<(Bool) -> Int>` +- 由上面这些类型组合而成的形参,例如 `(Optional<(Bool) -> Int>)...` 尾随闭包和结构上类似函数类型的形参匹配,但它并不是函数,所以闭包会按需包装。例如,如果形参类是是可选类型,闭包会自动包装成 `Optional` 。 - 为了简化 Swift 5.3 之前版本(从右到左匹配)的代码迁移 —— 编译器会同时检查从左到右和从右到左的顺序。如果不同的扫描方向产生了不同的结果,编译器则使用旧的从右到左的顺序,并生成警告。Swift 的未来版本将都使用从左到右的顺序。 ```swift @@ -1210,18 +1092,19 @@ someFunction { return $0 } secondClosure: { return $0 } // 打印 "10 20" 在上面的例子中,Swift 5.3 中被标记为“歧义”的函数调用会打印”- 120“并产生一个编辑器警告。未来版本的 Swift 会打印”110 -“。 -如 所述,通过声明几种方法中的一种,类、结构体或枚举类型可以为函数调用语法启用语法糖。 + +如 所述,通过声明几种方法中的一种,类、结构体或枚举类型可以为函数调用语法启用语法糖。 #### 指针类型的隐式转换 在函数调用表达式里,如果实参和形参的类型不一致,编译器会尝试通过下面的规则进行隐式转换来匹配类型: -- `inout SomeType` 可以成为 -`UnsafePointer` 或 `UnsafeMutablePointer` -- `inout Array` 可以成为 -`UnsafePointer`或`UnsafeMutablePointer` -- `Array`可以成为`UnsafePointer` -- `String`可以成为`UnsafePointer` +- `inout SomeType` can become + `UnsafePointer` or `UnsafeMutablePointer` +- `inout Array` can become + `UnsafePointer` or `UnsafeMutablePointer` +- `Array` can become `UnsafePointer` +- `String` can become `UnsafePointer` 下面两个函数调用是等价的: @@ -1237,12 +1120,19 @@ withUnsafePointer(to: myNumber) { unsafeFunction(pointer: $0) } 隐式转换创建的指针仅在函数调用期间有效。为了避免发生未定义行为,确保代码在函数调用结束后没有继续持有这些指针。 -> 注意 -> 当将数组隐式转换为不安全指针时,Swift 会按需转换或复制数组来确保数组的存储是连续的。例如,可以用此语法将没有> 约定存储 API 的 `NSArray` 子类桥接到 `Array` 的数组。如果能确保数组的存储是连续的,就不需要隐式转换来做这个工> 作,这种情况下可以用 `ContiguousArray` 代替 `Array`。 +> Note: When implicitly converting an array to an unsafe pointer, +> Swift ensures that the array's storage is contiguous +> by converting or copying the array as needed. +> For example, you can use this syntax +> with an array that was bridged to `Array` +> from an `NSArray` subclass that makes no API contract about its storage. +> If you need to guarantee that the array's storage is already contiguous, +> so the implicit conversion never needs to do this work, +> use `ContiguousArray` instead of `Array`. 使用 `&` 代替类似 `withUnsafePointer(to:)` 的显式函数可以在调用底层 C 函数的可读性更高,特别是当函数传入多个指针实参时。如果是其他 Swift 代码调用函数,避免使用 `&` 代替显式的不安全 API。 -> 函数调用表达式的语法: +> Grammar of a function call expression: > > *function-call-expression* → *postfix-expression* *function-call-argument-clause* \ > *function-call-expression* → *postfix-expression* *function-call-argument-clause*_?_ *trailing-closures* @@ -1258,10 +1148,10 @@ withUnsafePointer(to: myNumber) { unsafeFunction(pointer: $0) } ### 构造器表达式 -构造器表达式用于访问某个类型的构造器,形式如下: +*构造器表达式*用于访问某个类型的构造器,形式如下: ```swift -<#表达式#>.init(<#构造函数#>) +<#expression#>.init(<#initializer arguments#>) ``` 你可以在函数调用表达式中使用构造器表达式来初始化某个类型的新实例。也可以使用构造器表达式来代理给父类构造器。 @@ -1284,6 +1174,7 @@ let oneTwoThree = [1, 2, 3].map(initializer).reduce("", +) print(oneTwoThree) // 打印 "123" ``` + 如果通过名字来指定某个类型,可以不用构造器表达式而直接使用类型的构造器。在其他情况下,你必须使用构造器表达式。 ```swift @@ -1294,17 +1185,17 @@ let s3 = type(of: someValue).init(data: 7) // 有效 let s4 = type(of: someValue)(data: 5) // 错误 ``` -> 构造器表达式语法: +> Grammar of an initializer expression: > -> *构造器表达式语法* → *后缀表达式* **`.`** **`init`** \ -> *构造器表达式 * → *后缀表达式* **`.`** **`init`** **`(`** *参数名称* **`)`** +> *initializer-expression* → *postfix-expression* **`.`** **`init`** \ +> *initializer-expression* → *postfix-expression* **`.`** **`init`** **`(`** *argument-names* **`)`** ### 显式成员表达式 *显式成员表达式*允许我们访问命名类型、元组或者模块的成员,其形式如下: ```swift -<#表达名#>.<#成员名#> +<#expression#>.<#member name#> ``` 命名类型的某个成员在原始实现或者扩展中定义,例如: @@ -1316,16 +1207,18 @@ class SomeClass { let c = SomeClass() let y = c.someProperty // 访问成员 ``` -元组的成员按照它们出现的顺序使用整数隐式命名,从零开始。例如: + +元组的成员会隐式地根据表示它们出现顺序的整数来命名,以 0 开始,例如: ```swift var t = (10, 20, 30) t.0 = t.1 -// 现在元组 t 为 (20, 20, 30) +// 现在元组 (20, 20, 30) ``` + 对于模块的成员来说,只能直接访问顶级声明中的成员。 -使用 `dynamicMemberLookup` 属性声明的类型包含可以在运行时查找的成员,具体请参阅 。 +使用 `dynamicMemberLookup` 属性声明的类型包含可以在运行时查找的成员,具体请参阅 . 为了区分只有参数名有所不同的方法或构造器,在圆括号中写出参数名,参数名后紧跟一个冒号,对于没有参数名的参数,使用下划线代替参数名。而对于重载方法,则需使用类型注解进行区分。例如: @@ -1338,10 +1231,10 @@ class SomeClass { } let instance = SomeClass() -let a = instance.someMethod // 有歧义 -let b = instance.someMethod(x:y:) // 无歧义 +let a = instance.someMethod // Ambiguous +let b = instance.someMethod(x:y:) // Unambiguous -let d = instance.overloadedMethod // 有歧义 +let d = instance.overloadedMethod // Ambiguous let d = instance.overloadedMethod(x:y:) // Still ambiguous let d: (Int, Bool) -> Void = instance.overloadedMethod(x:y:) // Unambiguous ``` @@ -1354,7 +1247,8 @@ let x = [10, 3, 20, 15, 4] .filter { $0 > 5 } .map { $0 * 100 } ``` -你可以将这种多行链式语法与编译器控制语句结合,以控制调用每个方法的时间。例如,以下代码在 iOS 上应用了不同的过滤规则:: + +你可以将这种多行链式语法与编译器控制语句结合,以控制调用每个方法的时间。例如,以下代码在 iOS 上应用了不同的过滤规则: ```swift let numbers = [10, 20, 33, 43, 50] @@ -1364,13 +1258,14 @@ let numbers = [10, 20, 33, 43, 50] .filter { $0 > 25 } #endif ``` + 在 `#if`、`#endif` 和其它编译指令之间的条件编译块可以包含一个隐式成员表达式,后跟零个或多个后缀,以形成一个后缀表达式。这些条件编译块还可以包含另一个条件编译块,或者这些表达式和块的组合体。 除了顶级代码(top-level code)以外,你还可以在任何能编写显式成员表达式的地方使用上述语法。 在条件编译块中,编译指令 `#if` 的分支必须包含至少一个表达式,其它分支可以为空。 -> 显式成员表达式语法: +> Grammar of an explicit member expression: > > *explicit-member-expression* → *postfix-expression* **`.`** *decimal-digits* \ > *explicit-member-expression* → *postfix-expression* **`.`** *identifier* *generic-argument-clause*_?_ \ @@ -1380,49 +1275,48 @@ let numbers = [10, 20, 33, 43, 50] > *argument-names* → *argument-name* *argument-names*_?_ \ > *argument-name* → *identifier* **`:`** -### 后缀 self 表达式 +### 后缀 Self 表达式 -后缀`self` 表达式由某个表达式或类型名紧跟 `.self` 组成,其形式如下: +后缀 `self` 表达式由某个表达式或类型名紧跟 `.self` 组成,其形式如下: ```swift -<#表达式#>.self -<#类型#>.self +<#expression#>.self +<#type#>.self ``` 第一种形式返回表达式的值。例如:`x.self` 返回 `x`。 第二种形式返回相应的类型。我们可以用它来获取某个实例的类型作为一个值来使用。例如,`SomeClass.self` 会返回 `SomeClass` 类型本身,你可以将其传递给相应函数或者方法作为参数。 -> 后缀 self 表达式语法 +> Grammar of a postfix self expression: > -> *后缀 self 表达式* → * 后缀表达式* **`.`** **`self`** +> *postfix-self-expression* → *postfix-expression* **`.`** **`self`** ### 下标表达式 -可通过下标表达式访问相应的下标,形式如下: +可通过*下标表达式*访问相应的下标,形式如下: ```swift -<#表达式#>[<#索引表达式#>] +<#expression#>[<#index expressions#>] ``` 要获取下标表达式的值,可将索引表达式作为下标表达式的参数来调用下标 getter。下标 setter 的调用方式与之一样。 +关于下标的声明,请参阅 . -有关下标声明的信息,请参阅 . - -> 下标表达式语法: +> Grammar of a subscript expression: > > *subscript-expression* → *postfix-expression* **`[`** *function-call-argument-list* **`]`** ### 强制取值表达式 -当你确定可选值不是 `nil` 时,可以使用强制取值表达式来强制解包,形式如下: +当你确定可选值不是 `nil` 时,可以使用*强制取值表达式*来强制解包,形式如下: ```swift -<#表达式#>! +<#expression#>! ``` -如果该表达式的值不是 `nil`,则返回解包后的值。否则,抛出运行时错误。 +I如果该表达式的值不是 `nil`,则返回解包后的值。否则,抛出运行时错误。 返回的值可以被修改,无论是修改值本身,还是修改值的成员。例如: @@ -1435,28 +1329,31 @@ var someDictionary = ["a": [1, 2, 3], "b": [10, 20]] someDictionary["a"]![0] = 100 // someDictionary 现在是 ["a": [100, 2, 3], "b": [10, 20]] ``` -> 强制取值语法 + +> Grammar of a forced-value expression: > -> *强制值表达式* → *后缀表达式* **`!`** +> *forced-value-expression* → *postfix-expression* **`!`** -### 可选链式表达式 +### 可选链表达式 -*可选链表达式*提供了一种使用可选值的便捷方法,形式如下: +可选链表达式提供了一种使用可选值的便捷方法,形式如下: ```swift -<#表达式#>? +<#expression#>? ``` 后缀 `?` 运算符会根据表达式生成可选链表达式而不会改变表达式的值。 如果某个后缀表达式包含可选链表达式,那么它的执行过程会比较特殊。如果该可选链表达式的值是 `nil`,整个后缀表达式会直接返回 `nil`。如果该可选链表达式的值不是 `nil`,则返回可选链表达式解包后的值,并将该值用于后缀表达式中剩余的表达式。在这两种情况下,整个后缀表达式的值都会是可选类型。 -如果某个后缀表达式中包含了可选链表达式,那么只有最外层的表达式会返回一个可选类型。例如,在下面的例子中,如果 `c` 不是 `nil`,那么它的值会被解包,然后通过 `.property` 访问它的属性,接着进一步通过 `.performAction()` 调用相应方法。整个 `c?.property.performAction()` 表达式返回一个可选类型的值,而不是多重可选类型。 +如果某个后缀表达式中包含了可选链表达式,那么只有最外层的表达式会返回一个可选类型。例如,在下面的例子中,如果 c 不是 `nil`,那么它的值会被解包,然后通过 `.property` 访问它的属性,接着进一步通过 `.performAction()` 调用相应方法。整个 `c?.property.performAction()` 表达式返回一个可选类型的值,而不是多重可选类型。 ```swift var c: SomeClass? var result: Bool? = c?.property.performAction() ``` + + 上面的例子跟下面的不使用可选链表达式的例子等价: ```swift @@ -1465,6 +1362,7 @@ if let unwrappedC = c { result = unwrappedC.property.performAction() } ``` + 可选链表达式解包后的值可以被修改,无论是修改值本身,还是修改值的成员。如果可选链表达式的值为 `nil`,则表达式右侧的赋值操作不会被执行。例如: ```swift @@ -1481,13 +1379,14 @@ someDictionary["a"]?[0] = someFunctionWithSideEffects() // someFunctionWithSideEffects is evaluated and returns 42 // someDictionary is now ["a": [42, 2, 3], "b": [10, 20]] ``` -> 可选链表达式的语法: + +>可选链表达式语法: > > *可选链表达式* → *后缀表达式* **`?`** -> 测试版软件: +> 测试版软件: > -> 本文档包含有关正在开发的 API 或技术的初步信息。该信息可能会发生变化,并且根据本文档实现的软件应使用最终操作系统软件进行测试。. +> 此文档包含有关正在开发的 API 或技术的初步信息。这些信息可能会发生变化,按照此文档实现的软件应在最终操作系统软件下进行测试。 > -> 了解更多关于使用 [Apple's beta software](https://developer.apple.com/support/beta-software/). +> 了解更多关于使用的内容[Apple's beta software](https://developer.apple.com/support/beta-software/). From bcd5f9f00a086b8f0e691a9a0b985ac46767adf4 Mon Sep 17 00:00:00 2001 From: King <66349714+king-open@users.noreply.github.com> Date: Sun, 20 Oct 2024 23:16:13 +0800 Subject: [PATCH 13/14] =?UTF-8?q?docs=20=E4=BF=AE=E6=94=B9=20=E8=B5=8B?= =?UTF-8?q?=E5=80=BC=E8=BF=90=E7=AE=97=E7=AC=A6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- swift-6-beta.docc/ReferenceManual/Expressions.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/swift-6-beta.docc/ReferenceManual/Expressions.md b/swift-6-beta.docc/ReferenceManual/Expressions.md index a6610eb74..a55ecfb9a 100644 --- a/swift-6-beta.docc/ReferenceManual/Expressions.md +++ b/swift-6-beta.docc/ReferenceManual/Expressions.md @@ -153,7 +153,7 @@ sum = (await someAsyncFunction()) + anotherAsyncFunction() > *infix-expression* → *type-casting-operator* \ > *infix-expressions* → *infix-expression* *infix-expressions*_?_ -### 赋值表达式 +### 赋值赋值运算符 赋值表达式会为某个给定的表达式赋值,形式如下; From f27d6b9475cf56f35f0a1ba02efba4d3b72d0011 Mon Sep 17 00:00:00 2001 From: King <66349714+king-open@users.noreply.github.com> Date: Sun, 20 Oct 2024 23:22:58 +0800 Subject: [PATCH 14/14] =?UTF-8?q?docs=20=E4=BF=AE=E6=94=B9=20=E8=B5=8B?= =?UTF-8?q?=E5=80=BC=E8=BF=90=E7=AE=97=E7=AC=A6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- swift-6-beta.docc/ReferenceManual/Expressions.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/swift-6-beta.docc/ReferenceManual/Expressions.md b/swift-6-beta.docc/ReferenceManual/Expressions.md index a55ecfb9a..45024e546 100644 --- a/swift-6-beta.docc/ReferenceManual/Expressions.md +++ b/swift-6-beta.docc/ReferenceManual/Expressions.md @@ -153,9 +153,9 @@ sum = (await someAsyncFunction()) + anotherAsyncFunction() > *infix-expression* → *type-casting-operator* \ > *infix-expressions* → *infix-expression* *infix-expressions*_?_ -### 赋值赋值运算符 +### 赋值运算符 -赋值表达式会为某个给定的表达式赋值,形式如下; + 赋值运算符会为某个给定的表达式赋值,形式如下; ```swift <#表达式#> = <#值#>