swift5 modify
This commit is contained in:
@ -4,8 +4,7 @@
|
||||
|
||||
Swift 语言相对较小,这是由于 Swift 代码中常用的类型、函数以及运算符都已经在 Swift 标准库中定义了。虽然这些类型、函数和运算符并不是 Swift 语言自身的一部分,但是它们被广泛应用于本书的讨论和代码范例中。
|
||||
|
||||
<a name="how_to_read_the_grammar"></a>
|
||||
## 如何阅读语法
|
||||
## 如何阅读语法 {#how_to_read_the_grammar}
|
||||
|
||||
用来描述 Swift 编程语言形式语法的符号遵循下面几个约定:
|
||||
|
||||
@ -20,11 +19,14 @@ Swift 语言相对较小,这是由于 Swift 代码中常用的类型、函数
|
||||
|
||||
> getter-setter 方法块语法
|
||||
>
|
||||
> *getter-setter 方法块* → { [*getter 子句*](05_Declarations.html#getter-clause) [*setter 子句*](05_Declarations.html#setter-clause)<sub>可选</sub> } | { [*setter 子句*](05_Declarations.html#setter-clause) [*getter 子句*](05_Declarations.html#getter-clause) }
|
||||
> *getter-setter 方法块* → { [*getter 子句*](./06_Declarations.md#getter-clause) [*setter 子句*](./06_Declarations.md#setter-clause)<sub>可选</sub> } | { [*setter 子句*](./06_Declarations.md#setter-clause) [*getter 子句*](./06_Declarations.md#getter-clause) }
|
||||
>
|
||||
|
||||
这个定义表明,一个 getter-setter 方法块可以由一个 getter 分句后跟一个可选的 setter 分句构成,然后用大括号括起来,或者由一个 setter 分句后跟一个 getter 分句构成,然后用大括号括起来。上述的语法产式等价于下面的两个语法产式, :
|
||||
|
||||
> getter-setter 方法块语法
|
||||
>
|
||||
> getter-setter 方法块 → { [*getter 子句*](05_Declarations.html#getter-clause) [*setter 子句*](05_Declarations.html#setter-clause)<sub>可选</sub> }
|
||||
> getter-setter 方法块 → { [*setter 子句*](05_Declarations.html#setter-clause) [*getter 子句*](05_Declarations.html#getter-clause) }
|
||||
> getter-setter 方法块 → { [*getter 子句*](./06_Declarations.md#getter-clause) [*setter 子句*](./06_Declarations.md#setter-clause)<sub>可选</sub> }
|
||||
>
|
||||
> getter-setter 方法块 → { [*setter 子句*](./06_Declarations.md#setter-clause) [*getter 子句*](./06_Declarations.md#getter-clause) }
|
||||
>
|
||||
|
||||
@ -4,41 +4,56 @@ Swift 的*“词法结构(lexical structure)”* 描述了能构成该语言
|
||||
|
||||
通常情况下,通过考虑输入文本当中可能的最长子串,并且在随后将介绍的语法约束之下,根据随后将介绍的语法约束生成的,根据 Swift 源文件当中的字符来生成相应的“符号”。这种方法称为*“最长匹配(longest match)”*,或者*“最大适合(maximal munch)”*。
|
||||
|
||||
<a id="whitespace_and_comments"></a>
|
||||
## 空白与注释
|
||||
## 空白与注释 {#whitespace_and_comments}
|
||||
|
||||
空白(whitespace)有两个用途:分隔源文件中的符号以及帮助区分运算符属于前缀还是后缀(参见 [运算符](#operators)),在其他情况下空白则会被忽略。以下的字符会被当作空白:空格(U+0020)、换行符(U+000A)、回车符(U+000D)、水平制表符(U+0009)、垂直制表符(U+000B)、换页符(U+000C)以及空字符(U+0000)。
|
||||
|
||||
注释被编译器当作空白处理。单行注释由 `//` 开始直至遇到换行符(U+000A)或者回车符(U+000D)。多行注释由 `/*` 开始,以 `*/` 结束。注释允许嵌套,但注释标记必须匹配。
|
||||
|
||||
> 空白语法
|
||||
>
|
||||
|
||||
<a id="whitespace"></a>
|
||||
###### whitespace {#whitespace}
|
||||
> *空白* → [*空白项*](#whitespace-item) [*空白*](#whitespace)<sub>可选</sub>
|
||||
>
|
||||
> *空白项* → [*断行符*](#line-break)
|
||||
>
|
||||
> *空白项* → [*注释*](#comment)
|
||||
>
|
||||
> *空白项* → [*多行注释*](#multiline-comment)
|
||||
>
|
||||
> *空白项* → U+0000,U+0009,U+000B,U+000C 或者 U+0020
|
||||
>
|
||||
|
||||
<a id="line-break"></a>
|
||||
###### line-break {#line-break}
|
||||
> *断行符* → U+000A
|
||||
>
|
||||
> *断行符* → U+000D
|
||||
>
|
||||
> *断行符* → U+000D 接着是 U+000A
|
||||
>
|
||||
|
||||
<a id="comment"></a>
|
||||
###### comment {#comment}
|
||||
> *注释* → // [*注释内容 断行*](#comment-text line-break)
|
||||
>
|
||||
> *多行注释* → `/*` [*多行注释内容*](#multiline-commnet-text) `*/`
|
||||
>
|
||||
> *注释内容* → [*注释内容项*](#comment-text-item) [*注释内容*](#comment-text)<sub>可选</sub>
|
||||
>
|
||||
> *注释内容项* → 任何 Unicode 标量值, 除了 U+000A 或者 U+000D
|
||||
>
|
||||
> *多行注释内容* → [*多行注释内容项*](#multiline-comment-text-item) [*多行注释内容*](#multiline-comment-text)<sub>可选</sub>
|
||||
>
|
||||
> *多行注释内容项* → [*多行注释*](#multiline-comment).
|
||||
>
|
||||
> *多行注释内容项* → [*注释内容项*](#comment-text-item)
|
||||
>
|
||||
> *多行注释内容项* → 任何 Unicode 标量值, 除了 `/*` 或者 `*/`
|
||||
>
|
||||
|
||||
注释可以包含额外的格式和标记,正如 [*Markup Formatting Reference*](https://developer.apple.com/library/prerelease/ios/documentation/Xcode/Reference/xcode_markup_formatting_ref/index.html#//apple_ref/doc/uid/TP40016497) 所述。
|
||||
注释可以包含额外的格式和标记,正如 [*Markup Formatting Reference*](https://developer.apple.com/library/archive/documentation/Xcode/Reference/xcode_markup_formatting_ref/index.html) 所述。
|
||||
|
||||
<a id="identifiers"></a>
|
||||
## 标识符
|
||||
## 标识符 {#identifiers}
|
||||
|
||||
*标识符(identifier)* 可以由以下的字符开始:大写或小写的字母 `A` 到 `Z`、下划线(`_`)、基本多文种平面(Basic Multilingual Plane)中非字符数字组合的 Unicode 字符以及基本多文种平面以外的非个人专用区字符。在首字符之后,允许使用数字和组合 Unicode 字符。
|
||||
|
||||
@ -47,45 +62,71 @@ Swift 的*“词法结构(lexical structure)”* 描述了能构成该语言
|
||||
闭包中如果没有明确指定参数名称,参数将被隐式命名为 `$0`、`$1`、`$2` 等等。这些命名在闭包作用域范围内是合法的标识符。
|
||||
|
||||
> 标识符语法
|
||||
>
|
||||
|
||||
<a id="identifier"></a>
|
||||
###### identifier {#identifier}
|
||||
> *标识符* → [*头部标识符*](#identifier-head) [*标识符字符组*](#identifier-characters)<sub>可选</sub>
|
||||
>
|
||||
> *标识符* → \`[*头部标识符*](#identifier-head) [*标识符字符组*](#identifier-characters)<sub>可选</sub>\`
|
||||
>
|
||||
> *标识符* → [*隐式参数名*](#implicit-parameter-name)
|
||||
>
|
||||
|
||||
<a id="identifier-list"></a>
|
||||
###### identifier-list {#identifier-list}
|
||||
> *标识符列表* → [*标识符*](#identifier) | [*标识符*](#identifier) **,** [*标识符列表*](#identifier-list)
|
||||
>
|
||||
|
||||
<a id="identifier-head"></a>
|
||||
###### identifier-head {#identifier-head}
|
||||
> *头部标识符* → 大写或小写字母 A - Z
|
||||
>
|
||||
> *头部标识符* → _
|
||||
>
|
||||
> *头部标识符* → U+00A8,U+00AA,U+00AD,U+00AF,U+00B2–U+00B5,或者 U+00B7–U+00BA
|
||||
>
|
||||
> *头部标识符* → U+00BC–U+00BE,U+00C0–U+00D6,U+00D8–U+00F6,或者 U+00F8–U+00FF
|
||||
>
|
||||
> *头部标识符* → U+0100–U+02FF,U+0370–U+167F,U+1681–U+180D,或者 U+180F–U+1DBF
|
||||
>
|
||||
> *头部标识符* → U+1E00–U+1FFF
|
||||
>
|
||||
> *头部标识符* → U+200B–U+200D,U+202A–U+202E,U+203F–U+2040,U+2054,或者 U+2060–U+206F
|
||||
>
|
||||
> *头部标识符* → U+2070–U+20CF,U+2100–U+218F,U+2460–U+24FF,或者 U+2776–U+2793
|
||||
>
|
||||
> *头部标识符* → U+2C00–U+2DFF 或者 U+2E80–U+2FFF
|
||||
>
|
||||
> *头部标识符* → U+3004–U+3007,U+3021–U+302F,U+3031–U+303F,或者 U+3040–U+D7FF
|
||||
>
|
||||
> *头部标识符* → U+F900–U+FD3D,U+FD40–U+FDCF,U+FDF0–U+FE1F,或者 U+FE30–U+FE44
|
||||
>
|
||||
> *头部标识符* → U+FE47–U+FFFD
|
||||
>
|
||||
> *头部标识符* → U+10000–U+1FFFD,U+20000–U+2FFFD,U+30000–U+3FFFD,或者 U+40000–U+4FFFD
|
||||
>
|
||||
> *头部标识符* → U+50000–U+5FFFD,U+60000–U+6FFFD,U+70000–U+7FFFD,或者 U+80000–U+8FFFD
|
||||
>
|
||||
> *头部标识符* → U+90000–U+9FFFD,U+A0000–U+AFFFD,U+B0000–U+BFFFD,或者 U+C0000–U+CFFFD
|
||||
>
|
||||
> *头部标识符* → U+D0000–U+DFFFD 或者 U+E0000–U+EFFFD
|
||||
>
|
||||
|
||||
<a id="identifier-character"></a>
|
||||
###### identifier-character {#identifier-character}
|
||||
> *标识符字符* → 数值 0 - 9
|
||||
>
|
||||
> *标识符字符* → U+0300–U+036F,U+1DC0–U+1DFF,U+20D0–U+20FF,或者 U+FE20–U+FE2F
|
||||
>
|
||||
> *标识符字符* → [*头部标识符*](#identifier-head)
|
||||
> <a id="identifier-characters"></a>
|
||||
>
|
||||
> ###### identifier-characters {#identifier-characters}
|
||||
>
|
||||
> *标识符字符组* → [*标识符字符*](#identifier-character) [*标识符字符组*](#identifier-characters)<sub>可选</sub>
|
||||
>
|
||||
|
||||
<a id="implicit-parameter-name"></a>
|
||||
###### implicit-parameter-name {#implicit-parameter-name}
|
||||
> *隐式参数名* → **$** [*十进制数字列表*](#decimal-digits)
|
||||
>
|
||||
|
||||
<a id="keywords"></a>
|
||||
## 关键字和标点符号
|
||||
## 关键字和标点符号 {#keywords}
|
||||
|
||||
下面这些被保留的关键字不允许用作标识符,除非使用反引号转义,具体描述请参考 [标识符](#identifiers)。除了 `inout`、`var` 以及 `let` 之外的关键字可以用作某个函数声明或者函数调用当中的外部参数名,不用添加反引号转义。
|
||||
|
||||
@ -98,8 +139,7 @@ Swift 的*“词法结构(lexical structure)”* 描述了能构成该语言
|
||||
|
||||
以下符号被当作保留符号,不能用于自定义运算符: `(`、`)`、`{`、`}`、`[`、`]`、`.`、`,`、`:`、`;`、`=`、`@`、`#`、`&`(作为前缀运算符)、`->`、`` ` ``、`?`、`!`(作为后缀运算符)。
|
||||
|
||||
<a id="literals"></a>
|
||||
## 字面量
|
||||
## 字面量 {#literals}
|
||||
|
||||
*字面量(literal)* 用来表示源码中某种特定类型的值,比如一个数字或字符串。
|
||||
|
||||
@ -119,16 +159,21 @@ true // 布尔值字面量
|
||||
> 字面量语法
|
||||
>
|
||||
> *字面量* → [*数值字面量*](#numeric-literal) | [*字符串字面量*](#string-literal) | [*布尔值字面量*](#boolean-literal) | [*nil 字面量*](#nil-literal)
|
||||
>
|
||||
|
||||
<a id="numeric-literal"></a>
|
||||
###### numeric-literal {#numeric-literal}
|
||||
> *数值字面量* → **-**<sub>可选</sub> [*整数字面量*](#integer-literal) | **-**<sub>可选</sub> [*浮点数字面量*](#floating-point-literal)
|
||||
> <a id="boolean-literal"></a>
|
||||
>
|
||||
> ###### boolean-literal {#boolean-literal}
|
||||
>
|
||||
> *布尔值字面量* → **true** | **false**
|
||||
> <a id="nil-literal"></a>
|
||||
>
|
||||
> ###### nil-literal {#nil-literal}
|
||||
>
|
||||
> *nil 字面量* → **nil**
|
||||
>
|
||||
|
||||
<a id="integer_literals"></a>
|
||||
### 整数字面量
|
||||
### 整数字面量 {#integer_literals}
|
||||
|
||||
*整数字面量(Integer Literals)* 表示未指定精度整数的值。整数字面量默认用十进制表示,可以加前缀来指定其他的进制。二进制字面量加 `0b`,八进制字面量加 `0o`,十六进制字面量加 `0x`。
|
||||
|
||||
@ -138,56 +183,89 @@ true // 布尔值字面量
|
||||
|
||||
整型字面面可以使用下划线(`_`)来增加数字的可读性,下划线会被系统忽略,因此不会影响字面量的值。同样地,也可以在数字前加 `0`,这同样也会被系统所忽略,并不会影响字面量的值。
|
||||
|
||||
除非特别指定,整数字面量的默认推导类型为 Swift 标准库类型中的 `Int`。Swift 标准库还定义了其他不同长度以及是否带符号的整数类型,请参考 [整数](../chapter2/01_The_Basics.html#integers)。
|
||||
除非特别指定,整数字面量的默认推导类型为 Swift 标准库类型中的 `Int`。Swift 标准库还定义了其他不同长度以及是否带符号的整数类型,请参考 [整数](../chapter2/01_The_Basics.md#integers)。
|
||||
|
||||
> 整数字面量语法
|
||||
>
|
||||
<a id="integer-literal"></a>
|
||||
###### integer-literal {#integer-literal}
|
||||
> *整数字面量* → [*二进制字面量*](#binary-literal)
|
||||
>
|
||||
> *整数字面量* → [*八进制字面量*](#octal-literal)
|
||||
>
|
||||
> *整数字面量* → [*十进制字面量*](#decimal-literal)
|
||||
>
|
||||
> *整数字面量* → [*十六进制字面量*](#hexadecimal-literal)
|
||||
>
|
||||
|
||||
<a id="binary-literal"></a>
|
||||
###### binary-literal {#binary-literal}
|
||||
> *二进制字面量* → **0b** [*二进制数字*](#binary-digit) [*二进制字面量字符组*](#binary-literal-characters)<sub>可选</sub>
|
||||
> <a id="binary-digit"></a>
|
||||
>
|
||||
> ###### binary-digit {#binary-digit}
|
||||
>
|
||||
> *二进制数字* → 数值 0 到 1
|
||||
> <a id="binary-literal-character"></a>
|
||||
>
|
||||
> ###### binary-literal-character {#binary-literal-character}
|
||||
>
|
||||
> *二进制字面量字符* → [*二进制数字*](#binary-digit) | _
|
||||
> <a id="binary-literal-characters"></a>
|
||||
>
|
||||
> ###### binary-literal-characters {#binary-literal-characters}
|
||||
>
|
||||
> *二进制字面量字符组* → [*二进制字面量字符*](#binary-literal-character) [*二进制字面量字符组*](#binary-literal-characters)<sub>可选</sub>
|
||||
>
|
||||
|
||||
<a id="octal-literal"></a>
|
||||
###### octal-literal {#octal-literal}
|
||||
> *八进制字面量* → **0o** [*八进字数字*](#octal-digit) [*八进制字符组*](#octal-literal-characters)<sub>可选</sub>
|
||||
> <a id="octal-digit"></a>
|
||||
>
|
||||
> ###### octal-digit {#octal-digit}
|
||||
>
|
||||
> *八进字数字* → 数值 0 到 7
|
||||
> <a id="octal-literal-character"></a>
|
||||
>
|
||||
> ###### octal-literal-character {#octal-literal-character}
|
||||
>
|
||||
> *八进制字符* → [*八进字数字*](#octal-digit) | _
|
||||
> <a id="octal-literal-characters"></a>
|
||||
>
|
||||
> ###### octal-literal-characters {#octal-literal-characters}
|
||||
>
|
||||
> *八进制字符组* → [*八进制字符*](#octal-literal-character) [*八进制字符组*](#octal-literal-characters)<sub>可选</sub>
|
||||
>
|
||||
|
||||
<a id="decimal-literal"></a>
|
||||
###### decimal-literal {#decimal-literal}
|
||||
> *十进制字面量* → [*十进制数字*](#decimal-digit) [*十进制字符组*](#decimal-literal-characters)<sub>可选</sub>
|
||||
> <a id="decimal-digit"></a>
|
||||
>
|
||||
> ###### decimal-digit {#decimal-digit}
|
||||
>
|
||||
> *十进制数字* → 数值 0 到 9
|
||||
> <a id="decimal-digits"></a>
|
||||
>
|
||||
> ###### decimal-digits {#decimal-digits}
|
||||
>
|
||||
> *十进制数字组* → [*十进制数字*](#decimal-digit) [*十进制数字组*](#decimal-digits)<sub>可选</sub>
|
||||
> <a id="decimal-literal-character"></a>
|
||||
>
|
||||
> ###### decimal-literal-character {#decimal-literal-character}
|
||||
>
|
||||
> *十进制字符* → [*十进制数字*](#decimal-digit) | _
|
||||
> <a id="decimal-literal-characters"></a>
|
||||
>
|
||||
> ###### decimal-literal-characters {#decimal-literal-characters}
|
||||
>
|
||||
> *十进制字符组* → [*十进制字符*](#decimal-literal-character) [*十进制字符组*](#decimal-literal-characters)<sub>可选</sub>
|
||||
>
|
||||
|
||||
<a id="hexadecimal-literal"></a>
|
||||
###### hexadecimal-literal {#hexadecimal-literal}
|
||||
> *十六进制字面量* → **0x** [*十六进制数字*](#hexadecimal-digit) [*十六进制字面量字符组*](#hexadecimal-literal-characters)<sub>可选</sub>
|
||||
> <a id="hexadecimal-digit"></a>
|
||||
>
|
||||
> ###### hexadecimal-digit {#hexadecimal-digit}
|
||||
>
|
||||
> *十六进制数字* → 数值 0 到 9, 字母 a 到 f, 或 A 到 F
|
||||
> <a id="hexadecimal-literal-character"></a>
|
||||
>
|
||||
> ###### hexadecimal-literal-character {#hexadecimal-literal-character}
|
||||
>
|
||||
> *十六进制字符* → [*十六进制数字*](#hexadecimal-digit) | _
|
||||
> <a id="hexadecimal-literal-characters"></a>
|
||||
>
|
||||
> ###### hexadecimal-literal-characters {#hexadecimal-literal-characters}
|
||||
>
|
||||
> *十六进制字面量字符组* → [*十六进制字符*](#hexadecimal-literal-character) [*十六进制字面量字符组*](#hexadecimal-literal-characters)<sub>可选</sub>
|
||||
>
|
||||
|
||||
<a id="floating_point_literals"></a>
|
||||
### 浮点数字面量
|
||||
### 浮点数字面量 {#floating_point_literals}
|
||||
|
||||
*浮点数字面量(Floating-point literals)* 表示未指定精度浮点数的值。
|
||||
|
||||
@ -205,40 +283,56 @@ true // 布尔值字面量
|
||||
|
||||
> 浮点数字面量语法
|
||||
>
|
||||
<a id="floating-point-literal"></a>
|
||||
###### floating-point-literal {#floating-point-literal}
|
||||
> *浮点数字面量* → [*十进制字面量*](#decimal-literal) [*十进制分数*](#decimal-fraction)<sub>可选</sub> [*十进制指数*](#decimal-exponent)<sub>可选</sub>
|
||||
>
|
||||
> *浮点数字面量* → [*十六进制字面量*](#hexadecimal-literal) [*十六进制分数*](#hexadecimal-fraction)<sub>可选</sub> [*十六进制指数*](#hexadecimal-exponent)
|
||||
>
|
||||
|
||||
<a id="decimal-fraction"></a>
|
||||
###### decimal-fraction {#decimal-fraction}
|
||||
> *十进制分数* → **.** [*十进制字面量*](#decimal-literal)
|
||||
> <a id="decimal-exponent"></a>
|
||||
>
|
||||
> ###### decimal-exponent {#decimal-exponent}
|
||||
>
|
||||
> *十进制指数* → [*十进制指数 e*](#floating-point-e) [*正负号*](#sign)<sub>可选</sub> [*十进制字面量*](#decimal-literal)
|
||||
>
|
||||
|
||||
<a id="hexadecimal-fraction"></a>
|
||||
###### hexadecimal-fraction {#hexadecimal-fraction}
|
||||
> *十六进制分数* → **.** [*十六进制数字*](#hexadecimal-digit) [*十六进制字面量字符组*](#hexadecimal-literal-characters)<sub>可选</sub>
|
||||
> <a id="hexadecimal-exponent"></a>
|
||||
>
|
||||
> ###### hexadecimal-exponent {#hexadecimal-exponent}
|
||||
>
|
||||
> *十六进制指数* → [*十六进制指数 p*](#floating-point-p) [*正负号*](#sign)<sub>可选</sub> [*十进制字面量*](#decimal-literal)
|
||||
>
|
||||
|
||||
<a id="floating-point-e"></a>
|
||||
###### floating-point-e {#floating-point-e}
|
||||
> *十进制指数 e* → **e** | **E**
|
||||
> <a id="floating-point-p"></a>
|
||||
>
|
||||
> ###### floating-point-p {#floating-point-p}
|
||||
>
|
||||
> *十六进制指数 p* → **p** | **P**
|
||||
> <a id="sign"></a>
|
||||
>
|
||||
> ###### sign {#sign}
|
||||
>
|
||||
> *正负号* → **+** | **-**
|
||||
>
|
||||
|
||||
<a id="string_literals"></a>
|
||||
### 字符串字面量
|
||||
### 字符串字面量 {#string_literals}
|
||||
|
||||
字符串字面量是被引号包括的一串字符组成。 单行字符串字面量被包在双引号中的一串字符组成,形式如下:
|
||||
|
||||
> "`字符`"
|
||||
>
|
||||
|
||||
字符串字面量中不能包含未转义的双引号(`"`)、未转义的反斜线(`\`)、回车符、换行符。
|
||||
|
||||
多行字符串字面量被包在三个双引号中的一串字符组成,形式如下:
|
||||
> """
|
||||
>
|
||||
> `字符`
|
||||
>
|
||||
> """
|
||||
>
|
||||
|
||||
与单行字符串字面量不同的是,多行字符串字面量可以包含不转义的双引号("),回车以及换行。它不能包含三个非转义的连续双引号。
|
||||
|
||||
@ -273,7 +367,7 @@ true // 布尔值字面量
|
||||
let x = 3; "1 2 \(x)"
|
||||
```
|
||||
|
||||
字符串字面量的默认推导类型为 `String`。更多有关 `String` 类型的信息请参考 [字符串和字符](../chapter2/03_Strings_and_Characters.html) 以及 [*字符串结构参考*](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Reference/Swift_String_Structure/index.html#//apple_ref/doc/uid/TP40015181)。
|
||||
字符串字面量的默认推导类型为 `String`。更多有关 `String` 类型的信息请参考 [字符串和字符](../chapter2/03_Strings_and_Characters.md) 以及 [*字符串结构参考*](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Reference/Swift_String_Structure/index.md#//apple_ref/doc/uid/TP40015181)。
|
||||
|
||||
用 `+` 操作符连接的字符型字面量是在编译时进行连接的。比如下面的 `textA` 和 `textB` 是完全一样的,`textA` 没有任何运行时的连接操作。
|
||||
|
||||
@ -284,34 +378,49 @@ let textB = "Hello world"
|
||||
|
||||
> 字符串字面量语法
|
||||
>
|
||||
<a id="string-literal"></a>
|
||||
###### string-literal {#string-literal}
|
||||
> *字符串字面量* → [*静态字符串字面量*](#static-string-literal) | [*插值字符串字面量*](#interpolated-string-literal)
|
||||
>
|
||||
|
||||
<a id="static-string-literal"></a>
|
||||
###### static-string-literal {#static-string-literal}
|
||||
> *静态字符串字面量* → **"**[*引用文本*](#quoted-text)<sub>可选</sub>**"**
|
||||
> <a id="quoted-text"></a>
|
||||
>
|
||||
> ###### quoted-text {#quoted-text}
|
||||
>
|
||||
> *引用文本* → [*引用文本项*](#quoted-text-item) [*引用文本*](#quoted-text)<sub>可选</sub>
|
||||
> <a id="quoted-text-item"></a>
|
||||
>
|
||||
> ###### quoted-text-item {#quoted-text-item}
|
||||
>
|
||||
> *引用文本项* → [*转义字符*](#escaped-character)
|
||||
>
|
||||
> *引用文本项* → 除了 **"**、**\\**、U+000A、U+000D 以外的所有 Unicode 字符
|
||||
>
|
||||
|
||||
<a id="interpolated-string-literal"></a>
|
||||
###### interpolated-string-literal {#interpolated-string-literal}
|
||||
> *插值字符串字面量* → **"**[*插值文本*](#interpolated-text)<sub>可选</sub>**"**
|
||||
> <a id="interpolated-text"></a>
|
||||
>
|
||||
> ###### interpolated-text {#interpolated-text}
|
||||
>
|
||||
> *插值文本* → [*插值文本项*](#interpolated-text-item) [*插值文本*](#interpolated-text)<sub>可选</sub>
|
||||
> <a id="interpolated-text-item"></a>
|
||||
> *插值文本项* → **\\****(**[*表达式*](./04_Expressions.html)**)** | [*引用文本项*](#quoted-text-item)
|
||||
>
|
||||
> ###### interpolated-text-item {#interpolated-text-item}
|
||||
>
|
||||
> *插值文本项* → **\\****(**[*表达式*](./04_Expressions.md)**)** | [*引用文本项*](#quoted-text-item)
|
||||
>
|
||||
|
||||
<a id="escaped-character"></a>
|
||||
###### escaped-character {#escaped-character}
|
||||
> *转义字符* → **\\****0** | **\\****\\** | **\t** | **\n** | **\r** | **\\"** | **\\'**
|
||||
>
|
||||
> *转义字符* → **\u {** [*unicode 标量数字*](#unicode-scalar-digits) **}**
|
||||
> <a id="unicode-scalar-digits"></a>
|
||||
>
|
||||
> ###### unicode-scalar-digits {#unicode-scalar-digits}
|
||||
>
|
||||
> *unicode 标量数字* → 一到八位的十六进制数字
|
||||
>
|
||||
|
||||
<a id="operators"></a>
|
||||
## 运算符
|
||||
## 运算符 {#operators}
|
||||
|
||||
Swift 标准库定义了许多可供使用的运算符,其中大部分在 [基础运算符](../chapter2/02_Basic_Operators.html) 和 [高级运算符](../chapter2/25_Advanced_Operators.html) 中进行了阐述。这一小节将描述哪些字符能用于自定义运算符。
|
||||
Swift 标准库定义了许多可供使用的运算符,其中大部分在 [基础运算符](../chapter2/02_Basic_Operators.md) 和 [高级运算符](../chapter2/26_Advanced_Operators.md) 中进行了阐述。这一小节将描述哪些字符能用于自定义运算符。
|
||||
|
||||
自定义运算符可以由以下其中之一的 ASCII 字符 `/`、`=`、`-`、`+`、`!`、`*`、`%`、`<`、`>`、`&`、`|`、`^`、`?` 以及 `~`,或者后面语法中规定的任一个 Unicode 字符(其中包含了*数学运算符*、*零散符号(Miscellaneous Symbols)* 以及印刷符号(Dingbats)之类的 Unicode 块)开始。在第一个字符之后,允许使用组合型 Unicode 字符。
|
||||
|
||||
@ -322,6 +431,7 @@ Swift 标准库定义了许多可供使用的运算符,其中大部分在 [基
|
||||
> 注意
|
||||
>
|
||||
> 以下这些标记 `=`、`->`、`//`、`/*`、`*/`、`.`、`<`(前缀运算符)、`&`、`?`、`?`(中缀运算符)、`>`(后缀运算符)、`!` 、`?` 是被系统保留的。这些符号不能被重载,也不能用于自定义运算符。
|
||||
>
|
||||
|
||||
运算符两侧的空白被用来区分该运算符是否为前缀运算符、后缀运算符或二元运算符。规则总结如下:
|
||||
|
||||
@ -336,52 +446,88 @@ Swift 标准库定义了许多可供使用的运算符,其中大部分在 [基
|
||||
|
||||
在某些特定的设计中 ,以 `<` 或 `>` 开头的运算符会被分离成两个或多个符号,剩余部分可能会以同样的方式被再次分离。因此,在 `Dictionary<String, Array<Int>>` 中没有必要添加空白来消除闭合字符 `>` 的歧义。在这个例子中, 闭合字符 `>` 不会被视为单独的符号,因而不会被错误解析为 `>>` 运算符。
|
||||
|
||||
要学习如何自定义运算符,请参考 [自定义运算符](../chapter2/25_Advanced_Operators.html#custom_operators) 和 [运算符声明](05_Declarations.html#operator_declaration)。要学习如何重载运算符,请参考 [运算符函数](../chapter2/25_Advanced_Operators.html#operator_functions)。
|
||||
要学习如何自定义运算符,请参考 [自定义运算符](../chapter2/26_Advanced_Operators.md#custom_operators) 和 [运算符声明](./06_Declarations.md#operator_declaration)。要学习如何重载运算符,请参考 [运算符函数](../chapter2/26_Advanced_Operators.md#operator_functions)。
|
||||
|
||||
> 运算符语法
|
||||
>
|
||||
<a id="operator"></a>
|
||||
###### operator {#operator}
|
||||
> *运算符* → [*头部运算符*](#operator-head) [*运算符字符组*](#operator-characters)<sub>可选</sub>
|
||||
>
|
||||
> *运算符* → [*头部点运算符*](#dot-operator-head) [*点运算符字符组*](#dot-operator-characters)<sub>可选</sub>
|
||||
>
|
||||
|
||||
<a id="operator-head"></a>
|
||||
###### operator-head {#operator-head}
|
||||
> *头部运算符* → **/** | **=** | **-** | **+** | **!** | __*__ | **%** | **<** | **>** | **&** | **|** | **^** | **~** | **?**
|
||||
>
|
||||
> *头部运算符* → U+00A1–U+00A7
|
||||
>
|
||||
> *头部运算符* → U+00A9 或 U+00AB
|
||||
>
|
||||
> *头部运算符* → U+00AC 或 U+00AE
|
||||
>
|
||||
> *头部运算符* → U+00B0–U+00B1,U+00B6,U+00BB,U+00BF,U+00D7,或 U+00F7
|
||||
>
|
||||
> *头部运算符* → U+2016–U+2017 或 U+2020–U+2027
|
||||
>
|
||||
> *头部运算符* → U+2030–U+203E
|
||||
>
|
||||
> *头部运算符* → U+2041–U+2053
|
||||
>
|
||||
> *头部运算符* → U+2055–U+205E
|
||||
>
|
||||
> *头部运算符* → U+2190–U+23FF
|
||||
>
|
||||
> *头部运算符* → U+2500–U+2775
|
||||
>
|
||||
> *头部运算符* → U+2794–U+2BFF
|
||||
>
|
||||
> *头部运算符* → U+2E00–U+2E7F
|
||||
>
|
||||
> *头部运算符* → U+3001–U+3003
|
||||
>
|
||||
> *头部运算符* → U+3008–U+3030
|
||||
>
|
||||
|
||||
<a id="operator-character"></a>
|
||||
###### operator-character {#operator-character}
|
||||
> *运算符字符* → [*头部运算符*](#operator-head)
|
||||
>
|
||||
> *运算符字符* → U+0300–U+036F
|
||||
>
|
||||
> *运算符字符* → U+1DC0–U+1DFF
|
||||
>
|
||||
> *运算符字符* → U+20D0–U+20FF
|
||||
>
|
||||
> *运算符字符* → U+FE00–U+FE0F
|
||||
>
|
||||
> *运算符字符* → U+FE20–U+FE2F
|
||||
>
|
||||
> *运算符字符* → U+E0100–U+E01EF
|
||||
> <a id="operator-characters"></a>
|
||||
>
|
||||
> ###### operator-characters {#operator-characters}
|
||||
>
|
||||
> *运算符字符组* → [*运算符字符*](#operator-character) [*运算符字符组*](#operator-characters)<sub>可选</sub>
|
||||
>
|
||||
|
||||
<a id="dot-operator-head"></a>
|
||||
###### dot-operator-head {#dot-operator-head}
|
||||
> *头部点运算符* → **..**
|
||||
> <a id="dot-operator-character"></a>
|
||||
>
|
||||
> ###### dot-operator-character {#dot-operator-character}
|
||||
>
|
||||
> *点运算符字符* → **.** | [*运算符字符*](#operator-character)
|
||||
> <a id="dot-operator-characters"></a>
|
||||
>
|
||||
> ###### dot-operator-characters {#dot-operator-characters}
|
||||
>
|
||||
> *点运算符字符组* → [*点运算符字符*](#dot-operator-character) [*点运算符字符组*](#dot-operator-characters)<sub>可选</sub>
|
||||
>
|
||||
|
||||
<a id="binary-operator"></a>
|
||||
###### binary-operator {#binary-operator}
|
||||
> *二元运算符* → [*运算符*](#operator)
|
||||
> <a id="prefix-operator"></a>
|
||||
>
|
||||
> ###### prefix-operator {#prefix-operator}
|
||||
>
|
||||
> *前缀运算符* → [*运算符*](#operator)
|
||||
> <a id="postfix-operator"></a>
|
||||
>
|
||||
> ###### postfix-operator {#postfix-operator}
|
||||
>
|
||||
> *后缀运算符* → [*运算符*](#operator)
|
||||
>
|
||||
|
||||
@ -17,7 +17,7 @@
|
||||
|
||||
Swift 语言存在两种类型:命名型类型和复合型类型。*命名型类型*是指定义时可以给定名字的类型。命名型类型包括类、结构体、枚举和协议。比如,一个用户定义类 `MyClass` 的实例拥有类型 `MyClass`。除了用户定义的命名型类型,Swift 标准库也定义了很多常用的命名型类型,包括那些表示数组、字典和可选值的类型。
|
||||
|
||||
那些通常被其它语言认为是基本或原始的数据型类型,比如表示数字、字符和字符串的类型,实际上就是命名型类型,这些类型在 Swift 标准库中是使用结构体来定义和实现的。因为它们是命名型类型,因此你可以按照 [扩展](../chapter2/20_Extensions.html) 和 [扩展声明](06_Declarations.html#extension_declaration) 中讨论的那样,声明一个扩展来增加它们的行为以满足你程序的需求。
|
||||
那些通常被其它语言认为是基本或原始的数据型类型,比如表示数字、字符和字符串的类型,实际上就是命名型类型,这些类型在 Swift 标准库中是使用结构体来定义和实现的。因为它们是命名型类型,因此你可以按照 [扩展](../chapter2/20_Extensions.md) 和 [扩展声明](./06_Declarations.md#extension_declaration) 中讨论的那样,声明一个扩展来增加它们的行为以满足你程序的需求。
|
||||
|
||||
*复合型类型*是没有名字的类型,它由 Swift 本身定义。Swift 存在两种复合型类型:函数类型和元组类型。一个复合型类型可以包含命名型类型和其它复合型类型。例如,元组类型 `(Int, (Int, Int))` 包含两个元素:第一个是命名型类型 `Int`,第二个是另一个复合型类型 `(Int, Int)`。
|
||||
|
||||
@ -27,23 +27,33 @@ Swift 语言存在两种类型:命名型类型和复合型类型。*命名型
|
||||
|
||||
> 类型语法
|
||||
>
|
||||
<a name="type"></a>
|
||||
###### type {#type}
|
||||
> *类型* → [*数组类型*](#array-type)
|
||||
>
|
||||
> *类型* → [*字典类型*](#dictionary-type)
|
||||
>
|
||||
> *类型* → [*函数类型*](#function-type)
|
||||
>
|
||||
> *类型* → [*类型标识*](#type-identifier)
|
||||
>
|
||||
> *类型* → [*元组类型*](#tuple-type)
|
||||
>
|
||||
> *类型* → [*可选类型*](#optional-type)
|
||||
>
|
||||
> *类型* → [*隐式解析可选类型*](#implicitly-unwrapped-optional-type)
|
||||
>
|
||||
> *类型* → [*协议合成类型*](#protocol-composition-type)
|
||||
>
|
||||
> *类型* → [*元型类型*](#metatype-type)
|
||||
>
|
||||
> *类型* → **任意类型**
|
||||
>
|
||||
> *类型* → **自身类型**
|
||||
>
|
||||
> *类型* → [*(类型)*](#type)
|
||||
>
|
||||
|
||||
<a name="type_annotation"></a>
|
||||
## 类型注解
|
||||
|
||||
## 类型注解 {#type_annotation}
|
||||
*类型注解*显式地指定一个变量或表达式的类型。类型注解始于冒号 `:` 终于类型,比如下面两个例子:
|
||||
|
||||
```swift
|
||||
@ -57,12 +67,11 @@ func someFunction(a: Int) { /* ... */ }
|
||||
|
||||
> 类型注解语法
|
||||
>
|
||||
<a name="type-annotation"></a>
|
||||
> *类型注解* → **:** [*特性列表*](07_Attributes.html#attributes)<sub>可选</sub> **输入输出参数**<sub>可选</sub> [*类型*](#type)
|
||||
|
||||
<a name="type_identifier"></a>
|
||||
## 类型标识符
|
||||
###### type-annotation {#type-annotation}
|
||||
> *类型注解* → **:** [*特性列表*](./07_Attributes.md#attributes)<sub>可选</sub> **输入输出参数**<sub>可选</sub> [*类型*](#type)
|
||||
>
|
||||
|
||||
## 类型标识符 {#type_identifier}
|
||||
类型标识符引用命名型类型,还可引用命名型或复合型类型的别名。
|
||||
|
||||
大多数情况下,类型标识符引用的是与之同名的命名型类型。例如类型标识符 `Int` 引用命名型类型 `Int`,同样,类型标识符 `Dictionary<String, Int>` 引用命名型类型 `Dictionary<String, Int>`。
|
||||
@ -82,17 +91,17 @@ var someValue: ExampleModule.MyType
|
||||
|
||||
> 类型标识符语法
|
||||
>
|
||||
<a name="type-identifier"></a>
|
||||
> *类型标识符* → [*类型名称*](#type-name) [*泛型参数子句*](09_Generic_Parameters_and_Arguments.html#generic_argument_clause)<sub>可选</sub> | [*类型名称*](#type-name) [*泛型参数子句*](09_Generic_Parameters_and_Arguments.html#generic_argument_clause)<sub>可选</sub> **.** [*类型标识符*](#type-identifier)
|
||||
<a name="type-name"></a>
|
||||
> *类型名称* → [*标识符*](02_Lexical_Structure.html#identifier)
|
||||
|
||||
<a name="tuple_type"></a>
|
||||
## 元组类型
|
||||
###### type-identifier {#type-identifier}
|
||||
> *类型标识符* → [*类型名称*](#type-name) [*泛型参数子句*](./09_Generic_Parameters_and_Arguments.md#generic_argument_clause)<sub>可选</sub> | [*类型名称*](#type-name) [*泛型参数子句*](./09_Generic_Parameters_and_Arguments.md#generic_argument_clause)<sub>可选</sub> **.** [*类型标识符*](#type-identifier)
|
||||
>
|
||||
###### type-name {#type-name}
|
||||
> *类型名称* → [*标识符*](./02_Lexical_Structure.md#identifier)
|
||||
>
|
||||
|
||||
## 元组类型 {#tuple_type}
|
||||
元组类型是使用括号括起来的零个或多个类型,类型间用逗号隔开。
|
||||
|
||||
你可以使用元组类型作为一个函数的返回类型,这样就可以使函数返回多个值。你也可以命名元组类型中的元素,然后用这些名字来引用每个元素的值。元素的名字由一个标识符紧跟一个冒号 `(:)` 组成。[函数和多返回值](../chapter2/06_Functions.html#functions_with_multiple_return_values) 章节里有一个展示上述特性的例子。
|
||||
你可以使用元组类型作为一个函数的返回类型,这样就可以使函数返回多个值。你也可以命名元组类型中的元素,然后用这些名字来引用每个元素的值。元素的名字由一个标识符紧跟一个冒号 `(:)` 组成。[函数和多返回值](../chapter2/06_Functions.md#functions_with_multiple_return_values) 章节里有一个展示上述特性的例子。
|
||||
|
||||
当一个元组类型的元素有名字的时候,这个名字就是类型的一部分。
|
||||
|
||||
@ -107,29 +116,31 @@ someTuple = (left: 5, right: 5) // 错误:命名类型不匹配
|
||||
|
||||
> 元组类型语法
|
||||
>
|
||||
<a name="tuple-type"></a>
|
||||
###### tuple-type {#tuple-type}
|
||||
> *元组类型* → **(** **)** | **(** [*元组类型元素*](#tuple-type-element) **,** [*元组类型元素列表*](#tuple-type-element-list) **)**
|
||||
<a name="tuple-type-element-list"></a>
|
||||
>
|
||||
###### tuple-type-element-list {#tuple-type-element-list}
|
||||
> *元组类型元素列表* → [*元组类型元素*](#tuple-type-element) | [*元组类型元素*](#tuple-type-element) **,** [*元组类型元素列表*](#tuple-type-element-list)
|
||||
<a name="tuple-type-element"></a>
|
||||
>
|
||||
###### tuple-type-element {#tuple-type-element}
|
||||
> *元组类型元素* → [*元素名*](#element-name) [*类型注解*](#type-annotation) | [*类型*](#type)
|
||||
<a name="element-name"></a>
|
||||
> *元素名* → [*标识符*](02_Lexical_Structure.html#identifier)
|
||||
|
||||
<a name="function_type"></a>
|
||||
## 函数类型
|
||||
>
|
||||
###### element-name {#element-name}
|
||||
> *元素名* → [*标识符*](./02_Lexical_Structure.md#identifier)
|
||||
>
|
||||
|
||||
## 函数类型 {#function_type}
|
||||
函数类型表示一个函数、方法或闭包的类型,它由参数类型和返回值类型组成,中间用箭头(`->`)隔开:
|
||||
|
||||
> (`参数类型`)->(`返回值类型`)
|
||||
|
||||
*参数类型*是由逗号间隔的类型列表。由于*返回值类型*可以是元组类型,所以函数类型支持多返回值的函数与方法。
|
||||
|
||||
你可以对参数类型为 `() -> T`(其中 T 是任何类型)的函数使用 `autoclosure` 特性。这会自动将参数表达式转化为闭包,表达式的结果即闭包返回值。这从语法结构上提供了一种便捷:延迟对表达式的求值,直到其值在函数体中被调用。以自动闭包做为参数的函数类型的例子详见 [自动闭包](../chapter2/07_Closures.html#autoclosures)。
|
||||
你可以对参数类型为 `() -> T`(其中 T 是任何类型)的函数使用 `autoclosure` 特性。这会自动将参数表达式转化为闭包,表达式的结果即闭包返回值。这从语法结构上提供了一种便捷:延迟对表达式的求值,直到其值在函数体中被调用。以自动闭包做为参数的函数类型的例子详见 [自动闭包](../chapter2/07_Closures.md#autoclosures)。
|
||||
|
||||
函数类型可以拥有一个可变长参数作为*参数类型*中的最后一个参数。从语法角度上讲,可变长参数由一个基础类型名字紧随三个点(`...`)组成,如 `Int...`。可变长参数被认为是一个包含了基础类型元素的数组。即 `Int...` 就是 `[Int]`。关于使用可变长参数的例子,请参阅 [可变参数](../chapter2/06_Functions.html#variadic_parameters)。
|
||||
函数类型可以拥有一个可变长参数作为*参数类型*中的最后一个参数。从语法角度上讲,可变长参数由一个基础类型名字紧随三个点(`...`)组成,如 `Int...`。可变长参数被认为是一个包含了基础类型元素的数组。即 `Int...` 就是 `[Int]`。关于使用可变长参数的例子,请参阅 [可变参数](../chapter2/06_Functions.md#variadic_parameters)。
|
||||
|
||||
为了指定一个 `in-out` 参数,可以在参数类型前加 `inout` 前缀。但是你不可以对可变长参数或返回值类型使用 `inout`。关于这种参数的详细讲解请参阅 [输入输出参数](../chapter2/06_Functions.html#in_out_parameters)。
|
||||
为了指定一个 `in-out` 参数,可以在参数类型前加 `inout` 前缀。但是你不可以对可变长参数或返回值类型使用 `inout`。关于这种参数的详细讲解请参阅 [输入输出参数](../chapter2/06_Functions.md#in_out_parameters)。
|
||||
|
||||
如果一个函数类型只有一个形式参数而且形式参数的类型是元组类型,那么元组类型在写函数类型的时候必须用圆括号括起来。比如说,`((Int, Int)) -> Void` 是接收一个元组 `(Int, Int)` 作为形式参数并且不返回任何值的函数类型。与此相对,不加括号的 `(Int, Int) -> Void` 是一个接收两个 `Int` 作为形式参数并且不返回任何值的函数类型。相似地,因为 `Void` 是空元组类型 `()` 的别名,函数类型 `(Void)-> Void` 与 `(()) -> ()` 是一样的 - 一个将空元组作为唯一参数的函数。但这些类型和无变量的函数类型 `() -> ()` 是不一样的。
|
||||
|
||||
@ -141,13 +152,14 @@ func anotherFunction(left: Int, right: Int) {}
|
||||
func functionWithDifferentLabels(top: Int, bottom: Int) {}
|
||||
|
||||
var f = someFunction // 函数 f 的类型为 (Int, Int) -> Void, 而不是 (left: Int, right: Int) -> Void.
|
||||
|
||||
f = anotherFunction // 正确
|
||||
f = functionWithDifferentLabels // 正确
|
||||
|
||||
func functionWithDifferentArgumentTypes(left: Int, right: String) {}
|
||||
func functionWithDifferentNumberOfArguments(left: Int, right: Int, top: Int) {}
|
||||
|
||||
f = functionWithDifferentArgumentTypes // 错误
|
||||
|
||||
func functionWithDifferentNumberOfArguments(left: Int, right: Int, top: Int) {}
|
||||
f = functionWithDifferentNumberOfArguments // 错误
|
||||
```
|
||||
|
||||
@ -161,10 +173,9 @@ var operation: (Int, Int) -> Int // 正确
|
||||
|
||||
如果一个函数类型包涵多个箭头(->),那么函数类型将从右向左进行组合。例如,函数类型 `(Int) -> (Int) -> Int` 可以理解为 `(Int) -> ((Int) -> Int)`,也就是说,该函数类型的参数为 `Int` 类型,其返回类型是一个参数类型为 `Int`,返回类型为 `Int` 的函数。
|
||||
|
||||
函数类型若要抛出错误就必须使用 `throws` 关键字来标记,若要重抛错误则必须使用 `rethrows` 关键字来标记。`throws` 关键字是函数类型的一部分,非抛出函数是抛出函数函数的一个子类型。因此,在使用抛出函数的地方也可以使用不抛出函数。抛出和重抛函数的相关描述见章节 [抛出函数与方法](06_Declarations.html#throwing_functions_and_methods) 和 [重抛函数与方法](06_Declarations.html#rethrowing_functions_and_methods)。
|
||||
函数类型若要抛出错误就必须使用 `throws` 关键字来标记,若要重抛错误则必须使用 `rethrows` 关键字来标记。`throws` 关键字是函数类型的一部分,非抛出函数是抛出函数函数的一个子类型。因此,在使用抛出函数的地方也可以使用不抛出函数。抛出和重抛函数的相关描述见章节 [抛出函数与方法](./06_Declarations.md#throwing_functions_and_methods) 和 [重抛函数与方法](./06_Declarations.md#rethrowing_functions_and_methods)。
|
||||
|
||||
<a name="Restrictions for Nonescaping Closures"></a>
|
||||
### 对非逃逸闭包的限制
|
||||
### 对非逃逸闭包的限制 {#Restrictions for Nonescaping Closures}
|
||||
当非逃逸闭包函数是参数时,不能存储在属性、变量或任何 `Any` 类型的常量中,因为这可能导致值的逃逸。
|
||||
|
||||
当非逃逸闭包函数是参数时,不能作为参数传递到另一个非逃逸闭包函数中。这样的限制可以让 Swift 在编译时就完成更多的内存访问冲突检查,而不是在运行时。举个例子:
|
||||
@ -187,30 +198,34 @@ func takesTwoFunctions(first: (Any) -> Void, second: (Any) -> Void) {
|
||||
|
||||
上述例子里的被标记为“错误”的四个函数调用会产生编译错误。因为参数 `first` 和 `second` 是非逃逸函数,它们不能够作为参数被传递到另一个非闭包函数。相对的, 标记“正确”的两个函数不会产生编译错误。这些函数调用不会违反限制,因为 `external` 不是 `takesTwoFunctions(first:second:)` 的参数之一。
|
||||
|
||||
如果你需要避免这个限制,标记其中之一的参数为逃逸,或者使用 `withoutActuallyEscaping(_:do:)` 函数临时地转换非逃逸函数的其中一个参数为逃逸函数。关于避免内存访问冲突,可以参阅[内存安全](../chapter2/24_Memory_Safety.html)。
|
||||
|
||||
如果你需要避免这个限制,标记其中之一的参数为逃逸,或者使用 `withoutActuallyEscaping(_:do:)` 函数临时地转换非逃逸函数的其中一个参数为逃逸函数。关于避免内存访问冲突,可以参阅[内存安全](../chapter2/24_Memory_Safety.md)。
|
||||
|
||||
> 函数类型语法
|
||||
>
|
||||
<a name="function-type"></a>
|
||||
> *函数类型* → [*特性列表*](07_Attributes.html#attributes)<sub>可选</sub> [*函数类型子句*](#function-type-argument-clause) **throws**<sub>可选</sub> **->** [*类型*](#type)
|
||||
> *函数类型* → [*特性列表*](07_Attributes.html#attributes)<sub>可选</sub> [*函数类型子句*](#function-type-argument-clause) **rethrows** **->** [*类型*](#type)
|
||||
<a name="function-type-argument-clause"></a>
|
||||
> *函数类型子句* → **(** **)**
|
||||
> *函数类型子句* → **(** [*函数类型参数列表*](#function-type-argument-list)*...*<sub>可选</sub> **)**
|
||||
<a name="function-type-argument-list"></a>
|
||||
> *函数类型参数列表* → [*函数类型参数*](function-type-argument) | [*函数类型参数*](function-type-argument)**,** [*函数类型参数列表*](#function-type-argument-list)
|
||||
<a name="function-type-argument"></a>
|
||||
> *函数类型参数* → [*特性列表*](07_Attributes.html#attributes)<sub>可选</sub> **输入输出参数**<sub>可选</sub> [*类型*](#type) | [*参数标签*](#argument-label) [*类型注解*](#type-annotation)
|
||||
<a name="argument-label"></a>
|
||||
> *参数标签* → [*标识符*](02_Lexical_Structure.html#identifier)
|
||||
|
||||
<a name="array_type"></a>
|
||||
## 数组类型
|
||||
###### function-type {#function-type}
|
||||
> *函数类型* → [*特性列表*](./07_Attributes.md#attributes)<sub>可选</sub> [*函数类型子句*](#function-type-argument-clause) **throws**<sub>可选</sub> **->** [*类型*](#type)
|
||||
>
|
||||
> *函数类型* → [*特性列表*](./07_Attributes.md#attributes)<sub>可选</sub> [*函数类型子句*](#function-type-argument-clause) **rethrows** **->** [*类型*](#type)
|
||||
>
|
||||
###### function-type-argument-clause {#function-type-argument-clause}
|
||||
> *函数类型子句* → **(** **)**
|
||||
> *函数类型子句* → **(** [*函数类型参数列表*](#function-type-argument-list) *...* <sub>可选</sub> **)**
|
||||
>
|
||||
###### function-type-argument-list {#function-type-argument-list}
|
||||
> *函数类型参数列表* → [*函数类型参数*](function-type-argument) | [*函数类型参数*](function-type-argument), [*函数类型参数列表*](#function-type-argument-list)
|
||||
>
|
||||
###### function-type-argument {#function-type-argument}
|
||||
> *函数类型参数* → [*特性列表*](./07_Attributes.md#attributes)<sub>可选</sub> **输入输出参数**<sub>可选</sub> [*类型*](#type) | [*参数标签*](#argument-label) [*类型注解*](#type-annotation)
|
||||
>
|
||||
###### argument-label {#argument-label}
|
||||
> *参数标签* → [*标识符*](./02_Lexical_Structure.md#identifier)
|
||||
>
|
||||
|
||||
## 数组类型 {#array_type}
|
||||
Swift 语言为标准库中定义的 `Array<Element>` 类型提供了如下语法糖:
|
||||
|
||||
> [`类型`]
|
||||
>
|
||||
|
||||
换句话说,下面两个声明是等价的:
|
||||
|
||||
@ -229,19 +244,19 @@ var array3D: [[[Int]]] = [[[1, 2], [3, 4]], [[5, 6], [7, 8]]]
|
||||
|
||||
访问一个多维数组的元素时,最左边的下标指向最外层数组的相应位置元素。接下来往右的下标指向第一层嵌入的相应位置元素,依次类推。这就意味着,在上面的例子中,`array3D[0]` 是 `[[1, 2], [3, 4]]`,`array3D[0][1]` 是 `[3, 4]`,`array3D[0][1][1]` 则是 `4`。
|
||||
|
||||
关于 Swift 标准库中 `Array` 类型的详细讨论,请参阅 [数组](../chapter2/04_Collection_Types.html#arrays)。
|
||||
关于 Swift 标准库中 `Array` 类型的详细讨论,请参阅 [数组](../chapter2/04_Collection_Types.md#arrays)。
|
||||
|
||||
> 数组类型语法
|
||||
>
|
||||
<a name="array-type"></a>
|
||||
###### array-type {#array-type}
|
||||
> *数组类型* → **[** [*类型*](#type) **]**
|
||||
>
|
||||
|
||||
<a name="dictionary_type"></a>
|
||||
## 字典类型
|
||||
|
||||
## 字典类型 {#dictionary_type}
|
||||
Swift 语言为标准库中定义的 `Dictionary<Key, Value>` 类型提供了如下语法糖:
|
||||
|
||||
> [`键类型` : `值类型`]
|
||||
>
|
||||
|
||||
换句话说,下面两个声明是等价的:
|
||||
|
||||
@ -252,21 +267,20 @@ let someDictionary: Dictionary<String, Int> = ["Alex": 31, "Paul": 39]
|
||||
|
||||
上面两种情况,常量 `someDictionary` 被声明为一个字典,其中键为 `String` 类型,值为 `Int` 类型。
|
||||
|
||||
字典中的值可以通过下标来访问,这个下标在方括号中指明了具体的键:`someDictionary["Alex"]` 返回键 `Alex` 对应的值。如果键在字典中不存在的话,则这个下标返回 `nil`。
|
||||
字典中的值可以通过下标来访问,这个下标在方括号中指明了具体的键:`someDictionary["Alex"]` 返回键 `Alex` 对应的值。通过下标访问会获取对应值的可选类型。如果键在字典中不存在的话,则这个下标返回 `nil`。
|
||||
|
||||
字典中键的类型必须符合 Swift 标准库中的 `Hashable` 协议。
|
||||
|
||||
关于 Swift 标准库中 `Dictionary` 类型的详细讨论,请参阅 [字典](../chapter2/04_Collection_Types.html#dictionaries)。
|
||||
关于 Swift 标准库中 `Dictionary` 类型的详细讨论,请参阅 [字典](../chapter2/04_Collection_Types.md#dictionaries)。
|
||||
|
||||
> 字典类型语法
|
||||
>
|
||||
<a name="dictionary-type"></a>
|
||||
###### dictionary-type {#dictionary-type}
|
||||
> *字典类型* → **[** [*类型*](#type) **:** [*类型*](#type) **]**
|
||||
>
|
||||
|
||||
<a name="optional_type"></a>
|
||||
## 可选类型
|
||||
|
||||
Swift 定义后缀 `?` 来作为标准库中的定义的命名型类型 `Optional<Wrapped>` 的语法糖。换句话说,下面两个声明是等价的:
|
||||
## 可选类型 {#optional_type}
|
||||
Swift 定义后缀 `?` 来作为标准库中定义的命名型类型 `Optional<Wrapped>` 的语法糖。换句话说,下面两个声明是等价的:
|
||||
|
||||
```swift
|
||||
var optionalInteger: Int?
|
||||
@ -275,7 +289,7 @@ var optionalInteger: Optional<Int>
|
||||
|
||||
在上述两种情况下,变量 `optionalInteger` 都被声明为可选整型类型。注意在类型和 `?` 之间没有空格。
|
||||
|
||||
类型 `Optional<Wrapped>` 是一个枚举,有两个成员,`none` 和 `some(Wrapped)`,用来表示可能有也可能没有的值。任意类型都可以被显式地声明(或隐式地转换)为可选类型。如果你在声明或定义可选变量或属性的时候没有提供初始值,它的值则会自动赋为默认值 `nil`。
|
||||
类型 `Optional<Wrapped>` 是一个枚举,有两个成员,`none` 和 `some(Wrapped)`,用来表示可能有也可能没有的值。任意类型都可以被显式地声明(或隐式地转换)为可选类型。如果你在声明可选变量或属性的时候没有提供初始值,它的值则会自动赋为默认值 `nil`。
|
||||
|
||||
如果一个可选类型的实例包含一个值,那么你就可以使用后缀运算符 `!` 来获取该值,正如下面描述的:
|
||||
|
||||
@ -288,17 +302,16 @@ optionalInteger! // 42
|
||||
|
||||
你也可以使用可选链式调用和可选绑定来选择性地在可选表达式上执行操作。如果值为 `nil`,不会执行任何操作,因此也就没有运行错误产生。
|
||||
|
||||
更多细节以及更多如何使用可选类型的例子,请参阅 [可选类型](../chapter2/01_The_Basics.html#optionals)。
|
||||
更多细节以及更多如何使用可选类型的例子,请参阅 [可选类型](../chapter2/01_The_Basics.md#optionals)。
|
||||
|
||||
> 可选类型语法
|
||||
>
|
||||
<a name="optional-type"></a>
|
||||
###### optional-type {#optional-type}
|
||||
> *可选类型* → [*类型*](#type) **?**
|
||||
>
|
||||
|
||||
<a name="implicitly_unwrapped_optional_type"></a>
|
||||
## 隐式解析可选类型
|
||||
|
||||
当可以被访问时,Swift 语言定义后缀 `!` 作为标准库中命名类型 `Optional<Wrapped>` 的语法糖,来实现自动解包的功能。换句话说,下面两个声明等价:
|
||||
## 隐式解析可选类型 {#implicitly_unwrapped_optional_type}
|
||||
当可以被访问时,Swift 语言定义后缀 `!` 作为标准库中命名类型 `Optional<Wrapped>` 的语法糖,来实现自动解包的功能。如果尝试对一个值为 `nil` 的可选类型进行隐式解包,将会产生运行时错误。因为隐式解包,下面两个声明等价:
|
||||
|
||||
```swift
|
||||
var implicitlyUnwrappedString: String!
|
||||
@ -307,7 +320,7 @@ var explicitlyUnwrappedString: Optional<String>
|
||||
|
||||
注意类型与 `!` 之间没有空格。
|
||||
|
||||
由于隐式解包修改了包涵其类型的声明语义,嵌套在元组类型或泛型的可选类型(比如字典元素类型或数组元素类型),不能被标记为隐式解包。例如:
|
||||
由于隐式解包会更改包含该类型的声明语义,嵌套在元组类型或泛型中可选类型(比如字典元素类型或数组元素类型),不能被标记为隐式解包。例如:
|
||||
|
||||
```swift
|
||||
let tupleOfImplicitlyUnwrappedElements: (Int!, Int!) // 错误
|
||||
@ -317,49 +330,58 @@ let arrayOfImplicitlyUnwrappedElements: [Int!] // 错误
|
||||
let implicitlyUnwrappedArray: [Int]! // 正确
|
||||
```
|
||||
|
||||
由于隐式解析可选类型和可选类型有同样的表达式 `Optional<Wrapped>`,你可以在使用可选类型的地方使用隐式解析可选类型。比如,你可以将隐式解析可选类型的值赋给变量、常量和可选属性,反之亦然。
|
||||
由于隐式解析可选类型和可选类型有同样的类型 `Optional<Wrapped>`,你可以在所有使用可选类型的地方使用隐式解析可选类型。比如,你可以将隐式解析可选类型的值赋给变量、常量和可选属性,反之亦然。
|
||||
|
||||
正如可选类型一样,你在声明隐式解析可选类型的变量或属性的时候也不用指定初始值,因为它有默认值 `nil`。
|
||||
正如可选类型一样,如果你在声明隐式解析可选类型的变量或属性的时候没有指定初始值,它的值则会自动赋为默认值 `nil`。
|
||||
|
||||
可以使用可选链式调用来在隐式解析可选表达式上选择性地执行操作。如果值为 `nil`,就不会执行任何操作,因此也不会产生运行错误。
|
||||
可以使用可选链式调用对隐式解析可选表达式选择性地执行操作。如果值为 `nil`,就不会执行任何操作,因此也不会产生运行错误。
|
||||
|
||||
关于隐式解析可选类型的更多细节,请参阅 [隐式解析可选类型](../chapter2/01_The_Basics.html#implicityly_unwrapped_optionals)。
|
||||
关于隐式解析可选类型的更多细节,请参阅 [隐式解析可选类型](../chapter2/01_The_Basics.md#implicityly_unwrapped_optionals)。
|
||||
|
||||
> 隐式解析可选类型语法
|
||||
>
|
||||
<a name="implicitly-unwrapped-optional-type"></a>
|
||||
###### implicitly-unwrapped-optional-type {#implicitly-unwrapped-optional-type}
|
||||
> *隐式解析可选类型* → [*类型*](#type) **!**
|
||||
>
|
||||
|
||||
<a name="protocol_composition_type"></a>
|
||||
## 协议合成类型
|
||||
|
||||
协议合成类型是一种符合协议列表中每个指定协议的类型。协议合成类型可能会用在类型注解和泛型参数中。
|
||||
## 协议合成类型 {#protocol_composition_type}
|
||||
协议合成类型定义了一种遵循协议列表中每个指定协议的类型,或者一个现有类型的子类并遵循协议列表中每个指定协议。协议合成类型只能用在类型注解、泛型参数子句和泛型 `where` 子句中指定类型。
|
||||
|
||||
协议合成类型的形式如下:
|
||||
|
||||
> `Protocol 1` & `Procotol 2`
|
||||
>
|
||||
|
||||
协议合成类型允许你指定一个值,其类型符合多个协议的要求且不需要定义一个新的命名型协议来继承它想要符合的各个协议。比如,协议合成类型 `Protocol A & Protocol B & Protocol C` 等效于一个从 `Protocol A`,`Protocol B`,`Protocol C` 继承而来的新协议 `Protocol D`,很显然这样做有效率的多,甚至不需引入一个新名字。
|
||||
协议合成类型允许你指定一个值,其类型遵循多个协议的要求而不需要定义一个新的命名型协议来继承它想要符合的各个协议。比如,协议合成类型 `Protocol A & Protocol B & Protocol C` 等效于一个从 `Protocol A`,`Protocol B`,`Protocol C` 继承而来的新协议。同样的,你可以使用 `SuperClass & ProtocolA` 来取代申明一个新的协议作为 `SuperClass` 的子类并遵循 `ProtocolA`。
|
||||
|
||||
协议合成列表中的每项必须是协议名或协议合成类型的类型别名。
|
||||
协议合成列表中的每一项都必须是下面所列情况之一,列表中最多只能包含一个类:
|
||||
|
||||
- 类名
|
||||
- 协议名
|
||||
- 一个类型别名,它的潜在类型是一个协议合成类型、一个协议或者一个类
|
||||
|
||||
当协议合成类型包含类型别名时,同一个协议可能多次出现在定义中 — 重复被忽略。例如,下面代码中定义的 `PQR` 等同于 `P & Q & R`。
|
||||
|
||||
```swift
|
||||
typealias PQ = P & Q
|
||||
typealias PQR = PQ & Q & R
|
||||
```
|
||||
|
||||
> 协议合成类型语法
|
||||
>
|
||||
<a name="protocol-composition-type"></a>
|
||||
###### protocol-composition-type {#protocol-composition-type}
|
||||
> *协议合成类型* → [*协议标识符*](#protocol-identifier) & [*协议合成延续*](#protocol-composition-continuation)
|
||||
<a name="protocol-composition-continuation"></a>
|
||||
>
|
||||
###### protocol-composition-continuation {#protocol-composition-continuation}
|
||||
> *协议合成延续* → [*协议标识符*](#protocol-identifier) | [*协议合成类型*](#protocol-composition-type)
|
||||
<a name="protocol-identifier"></a>
|
||||
> *协议标识符* → [*类型标识符*](#type-identifier)
|
||||
>
|
||||
|
||||
<a name="metatype_type"></a>
|
||||
## 元类型
|
||||
## 元类型 {#metatype_type}
|
||||
元类型是指任意类型的类型,包括类类型、结构体类型、枚举类型和协议类型。
|
||||
|
||||
元类型是指类型的类型,包括类类型、结构体类型、枚举类型和协议类型。
|
||||
类、结构体或枚举类型的元类型是相应的类型名紧跟 `.Type`。协议类型的元类型——并不是运行时遵循该协议的具体类型——是该协议名字紧跟 `.Protocol`。比如,类 `SomeClass` 的元类型就是 `SomeClass.Type`,协议 `SomeProtocol` 的元类型就是 `SomeProtocal.Protocol`。
|
||||
|
||||
类、结构体或枚举类型的元类型是相应的类型名紧跟 `.Type`。协议类型的元类型——并不是运行时符合该协议的具体类型——而是该协议名字紧跟 `.Protocol`。比如,类 `SomeClass` 的元类型就是 `SomeClass.Type`,协议 `SomeProtocol` 的元类型就是 `SomeProtocal.Protocol`。
|
||||
|
||||
你可以使用后缀 `self` 表达式来获取类型。比如,`SomeClass.self` 返回 `SomeClass` 本身,而不是 `SomeClass` 的一个实例。同样,`SomeProtocol.self` 返回 `SomeProtocol` 本身,而不是运行时符合 `SomeProtocol` 的某个类型的实例。还可以对类型的实例使用 `type(of:)` 表达式来获取该实例在运行阶段的类型,如下所示:
|
||||
你可以使用后缀 `self` 表达式来获取类型。比如,`SomeClass.self` 返回 `SomeClass` 本身,而不是 `SomeClass` 的一个实例。同样,`SomeProtocol.self` 返回 `SomeProtocol` 本身,而不是运行时遵循 `SomeProtocol` 的某个类型的实例。还可以对类型的实例使用 `type(of:)` 表达式来获取该实例动态的、在运行阶段的类型,如下所示:
|
||||
|
||||
```swift
|
||||
class SomeBaseClass {
|
||||
@ -379,7 +401,7 @@ type(of: someInstance).printClassName()
|
||||
// 打印“SomeSubClass”
|
||||
```
|
||||
|
||||
更多信息可以查看 Swift 标准库里的 `type(of:)`。
|
||||
更多信息可以查看 Swift 标准库里的 [type(of:)](https://developer.apple.com/documentation/swift/2885064-type)。
|
||||
|
||||
可以使用初始化表达式从某个类型的元类型构造出一个该类型的实例。对于类实例,被调用的构造器必须使用 `required` 关键字标记,或者整个类使用 `final` 关键字标记。
|
||||
|
||||
@ -399,32 +421,31 @@ let anotherInstance = metatype.init(string: "some string")
|
||||
|
||||
> 元类型语法
|
||||
>
|
||||
<a name="metatype-type"></a>
|
||||
###### metatype-type {#metatype-type}
|
||||
> *元类型* → [*类型*](#type) **.** **Type** | [*类型*](#type) **.** **Protocol**
|
||||
>
|
||||
|
||||
<a name="type_inheritance_clause"></a>
|
||||
## 类型继承子句
|
||||
## 类型继承子句 {#type_inheritance_clause}
|
||||
类型继承子句被用来指定一个命名型类型继承自哪个类、采纳哪些协议。类型继承子句开始于冒号 `:`,其后是类型标识符列表。
|
||||
|
||||
类型继承子句被用来指定一个命名型类型继承自哪个类、采纳哪些协议。类型继承子句也用来指定一个类类型专属协议。类型继承子句开始于冒号 `:`,其后是所需要的类、类型标识符列表或两者都有。
|
||||
类可以继承自单个超类,并遵循任意数量的协议。当定义一个类时,超类的名字必须出现在类型标识符列表首位,然后跟上该类需要遵循的任意数量的协议。如果一个类不是从其它类继承而来,那么列表可以以协议开头。关于类继承更多的讨论和例子,请参阅 [继承](../chapter2/13_Inheritance.md)。
|
||||
|
||||
类可以继承单个超类,采纳任意数量的协议。当定义一个类时,超类的名字必须出现在类型标识符列表首位,然后跟上该类需要采纳的任意数量的协议。如果一个类不是从其它类继承而来,那么列表可以以协议开头。关于类继承更多的讨论和例子,请参阅 [继承](../chapter2/13_Inheritance.html)。
|
||||
其它命名型类型只能继承自或采纳一系列协议。协议类型可以继承自任意数量的其他协议。当一个协议类型继承自其它协议时,其它协议中定义的要求会被整合在一起,然后从当前协议继承的任意类型必须符合所有这些条件。
|
||||
|
||||
其它命名型类型可能只继承或采纳一系列协议。协议类型可以继承自任意数量的其他协议。当一个协议类型继承自其它协议时,其它协议中定义的要求会被整合在一起,然后从当前协议继承的任意类型必须符合所有这些条件。正如在 [协议声明](05_Declarations.html#protocol_declaration) 中所讨论的那样,可以把 `class` 关键字放到协议类型的类型继承子句的首位,这样就可以声明一个类类型专属协议。
|
||||
|
||||
枚举定义中的类型继承子句可以是一系列协议,或是枚举的原始值类型的命名型类型。在枚举定义中使用类型继承子句来指定原始值类型的例子,请参阅 [原始值](../chapter2/08_Enumerations.html#raw_values)。
|
||||
枚举定义中的类型继承子句可以是一系列协议,或者是指定单一的命名类型,此时枚举为其用例分配原始值。在枚举定义中使用类型继承子句来指定原始值类型的例子,请参阅 [原始值](../chapter2/08_Enumerations.md#raw_values)。
|
||||
|
||||
> 类型继承子句语法
|
||||
>
|
||||
<a name="type_inheritance_clause"></a>
|
||||
###### type_inheritance_clause {#type_inheritance_clause}
|
||||
> *类型继承子句* → **:** [*类型继承列表*](#type-inheritance-list)
|
||||
<a name="type-inheritance-list"></a>
|
||||
>
|
||||
###### type-inheritance-list {#type-inheritance-list}
|
||||
> *类型继承列表* → [*类型标识符*](#type-identifier) | [*类型标识符*](#type-identifier) **,** [*类型继承列表*](#type-inheritance-list)
|
||||
<a name="class-requirement"></a>
|
||||
>
|
||||
###### class-requirement {#class-requirement}
|
||||
|
||||
|
||||
<a name="type_inference"></a>
|
||||
## 类型推断
|
||||
|
||||
## 类型推断 {#type_inference}
|
||||
Swift 广泛使用类型推断,从而允许你省略代码中很多变量和表达式的类型或部分类型。比如,对于 `var x: Int = 0`,你可以完全省略类型而简写成 `var x = 0`,编译器会正确推断出 `x` 的类型 `Int`。类似的,当完整的类型可以从上下文推断出来时,你也可以省略类型的一部分。比如,如果你写了 `let dict: Dictionary = ["A" : 1]`,编译器能推断出 `dict` 的类型是 `Dictionary<String, Int>`。
|
||||
|
||||
在上面的两个例子中,类型信息从表达式树的叶子节点传向根节点。也就是说,`var x: Int = 0` 中 `x` 的类型首先根据 `0` 的类型进行推断,然后将该类型信息传递到根节点(变量 `x`)。
|
||||
@ -436,4 +457,4 @@ let e = 2.71828 // e 的类型会被推断为 Double
|
||||
let eFloat: Float = 2.71828 // eFloat 的类型为 Float
|
||||
```
|
||||
|
||||
Swift 中的类型推断在单独的表达式或语句上进行。这意味着所有用于类型推断的信息必须可以从表达式或其某个子表达式的类型检查中获取到。
|
||||
Swift 中的类型推断在单独的表达式或语句上进行。这意味着所有用于类型推断的信息必须可以从表达式或其某个子表达式的类型检查中获取到。
|
||||
@ -6,46 +6,50 @@ Swift 中存在四种表达式:前缀表达式,二元表达式,基本表
|
||||
|
||||
> 表达式语法
|
||||
>
|
||||
<a name="expression"></a>
|
||||
###### expression {#expression}
|
||||
> *表达式* → [*try 运算符*](#try-operator)<sub>可选</sub> [*前缀表达式*](#prefix-expression) [*二元表达式列表*](#binary-expressions)<sub>可选</sub>
|
||||
<a name="expression-list"></a>
|
||||
>
|
||||
###### expression-list {#expression-list}
|
||||
> *表达式列表* → [*表达式*](#expression) | [*表达式*](#expression) **,** [*表达式列表*](#expression-list)
|
||||
>
|
||||
|
||||
<a name="prefix_expressions"></a>
|
||||
## 前缀表达式
|
||||
|
||||
## 前缀表达式 {#prefix_expressions}
|
||||
前缀表达式由可选的前缀运算符和表达式组成。前缀运算符只接收一个参数,表达式则紧随其后。
|
||||
|
||||
关于这些运算符的更多信息,请参阅 [基本运算符](../chapter2/02_Basic_Operators.md) 和 [高级运算符](../chapter2/25_Advanced_Operators.md)。
|
||||
关于这些运算符的更多信息,请参阅 [基本运算符](../chapter2/02_Basic_Operators.md) 和 [高级运算符](../chapter2/26_Advanced_Operators.md)。
|
||||
|
||||
关于 Swift 标准库提供的运算符的更多信息,请参阅 [*Swift Standard Library Operators Reference*](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Reference/Swift_StandardLibrary_Operators/index.html#//apple_ref/doc/uid/TP40016054)。
|
||||
关于 Swift 标准库提供的运算符的更多信息,请参阅 [*Operators Declarations*](https://developer.apple.com/documentation/swift/swift_standard_library/operator_declarations)。
|
||||
|
||||
除了标准库运算符,你也可以对某个变量使用 `&` 运算符,从而将其传递给函数的输入输出参数。更多信息,请参阅 [输入输出参数](../chapter2/06_Functions.html#in_out_parameters)。
|
||||
除了标准库运算符,你也可以对某个变量使用 `&` 运算符,从而将其传递给函数的输入输出参数。更多信息,请参阅 [输入输出参数](../chapter2/06_Functions.md#in_out_parameters)。
|
||||
|
||||
> 前缀表达式语法
|
||||
>
|
||||
<a name="prefix-expression"></a>
|
||||
> *前缀表达式* → [*前缀运算符*](02_Lexical_Structure.md#prefix-operator)<sub>可选</sub> [*后缀表达式*](#postfix-expression)
|
||||
###### prefix-expression {#prefix-expression}
|
||||
> *前缀表达式* → [*前缀运算符*](./02_Lexical_Structure.md#prefix-operator)<sub>可选</sub> [*后缀表达式*](#postfix-expression)
|
||||
>
|
||||
> *前缀表达式* → [*输入输出表达式*](#in-out-expression)
|
||||
<a name="in-out-expression"></a>
|
||||
> *输入输出表达式* → **&** [*标识符*](02_Lexical_Structure.md#identifier)
|
||||
|
||||
<a name="try_operator"></a>
|
||||
### Try 运算符
|
||||
>
|
||||
###### in-out-expression {#in-out-expression}
|
||||
> *输入输出表达式* → **&** [*标识符*](./02_Lexical_Structure.md#identifier)
|
||||
>
|
||||
|
||||
### Try 运算符 {#try_operator}
|
||||
try 表达式由 `try` 运算符加上紧随其后的可抛出错误的表达式组成,形式如下:
|
||||
|
||||
> try `可抛出错误的表达式`
|
||||
>
|
||||
|
||||
可选的 try 表达式由 `try?` 运算符加上紧随其后的可抛出错误的表达式组成,形式如下:
|
||||
|
||||
> try? `可抛出错误的表达式`
|
||||
>
|
||||
|
||||
如果可抛出错误的表达式没有抛出错误,整个表达式返回的可选值将包含可抛出错误的表达式的返回值,否则,该可选值为 `nil`。
|
||||
|
||||
强制的 try 表达式由 `try!` 运算符加上紧随其后的可抛出错误的表达式组成,形式如下:
|
||||
|
||||
> try! `可抛出错误的表达式`
|
||||
>
|
||||
|
||||
如果可抛出错误的表达式抛出了错误,将会引发运行时错误。
|
||||
|
||||
@ -59,43 +63,48 @@ sum = (try someThrowingFunction()) + anotherThrowingFunction() // 错误:try
|
||||
|
||||
`try` 表达式不能出现在二进制运算符的的右侧,除非二进制运算符是赋值运算符或者 `try` 表达式是被圆括号括起来的。
|
||||
|
||||
关于 `try`、`try?` 和 `try!` 的更多信息,以及该如何使用的例子,请参阅 [错误处理](../chapter2/18_Error_Handling.html)。
|
||||
关于 `try`、`try?` 和 `try!` 的更多信息,以及该如何使用的例子,请参阅 [错误处理](../chapter2/17_Error_Handling.md)。
|
||||
> Try 表达式语法
|
||||
>
|
||||
<a name="try-operator"></a>
|
||||
###### try-operator {#try-operator}
|
||||
> *try 运算符* → **try** | **try?** | **try!**
|
||||
>
|
||||
|
||||
<a name="binary_expressions"></a>
|
||||
## 二元表达式
|
||||
|
||||
## 二元表达式 {#binary_expressions}
|
||||
*二元表达式*由中缀运算符和左右参数表达式组成。形式如下:
|
||||
|
||||
> `左侧参数` `二元运算符` `右侧参数`
|
||||
>
|
||||
|
||||
关于这些运算符的更多信息,请参阅 [基本运算符](../chapter2/02_Basic_Operators.html) 和 [高级运算符](../chapter2/26_Advanced_Operators.html)。
|
||||
关于这些运算符的更多信息,请参阅 [基本运算符](../chapter2/02_Basic_Operators.md) 和 [高级运算符](../chapter2/26_Advanced_Operators.md)。
|
||||
|
||||
关于 Swift 标准库提供的运算符的更多信息,请参阅 [*Swift Standard Library Operators Reference*](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Reference/Swift_StandardLibrary_Operators/index.html#//apple_ref/doc/uid/TP40016054)。
|
||||
关于 Swift 标准库提供的运算符的更多信息,请参阅 [*Swift Standard Library Operators Reference*](./https://developer.apple.com/library/prerelease/ios/documentation/Swift/Reference/Swift_StandardLibrary_Operators/index.md#//apple_ref/doc/uid/TP40016054)。
|
||||
|
||||
> 注意
|
||||
>
|
||||
> 在解析时,一个二元表达式将作为一个扁平列表表示,然后根据运算符的优先级,再进一步进行组合。例如,`2 + 3 * 5` 首先被看作具有五个元素的列表,即 `2`、`+`、`3`、`*`、`5`,随后根据运算符优先级组合为 `(2 + (3 * 5))`。
|
||||
>
|
||||
|
||||
<a name="binary-expression"></a>
|
||||
###### binary-expression {#binary-expression}
|
||||
> 二元表达式语法
|
||||
>
|
||||
> *二元表达式* → [*二元运算符*](02_Lexical_Structure.md#binary-operator) [*前缀表达式*](#prefix-expression)
|
||||
> *二元表达式* → [*二元运算符*](./02_Lexical_Structure.md#binary-operator) [*前缀表达式*](#prefix-expression)
|
||||
>
|
||||
> *二元表达式* → [*赋值运算符*](#assignment-operator) [*try 运算符*](#try-operator)<sub>可选</sub> [*前缀表达式*](#prefix-expression)
|
||||
>
|
||||
> *二元表达式* → [*条件运算符*](#conditional-operator) [*try 运算符*](#try-operator)<sub>可选</sub> [*前缀表达式*](#prefix-expression)
|
||||
>
|
||||
> *二元表达式* → [*类型转换运算符*](#type-casting-operator)
|
||||
<a name="binary-expressions"></a>
|
||||
>
|
||||
###### binary-expressions {#binary-expressions}
|
||||
> *二元表达式列表* → [*二元表达式*](#binary-expression) [*二元表达式列表*](#binary-expressions)<sub>可选</sub>
|
||||
>
|
||||
|
||||
<a name="assignment_operator"></a>
|
||||
### 赋值表达式
|
||||
|
||||
### 赋值表达式 {#assignment_operator}
|
||||
赋值表达式会为某个给定的表达式赋值,形式如下;
|
||||
|
||||
> `表达式` = `值`
|
||||
>
|
||||
|
||||
右边的值会被赋值给左边的表达式。如果左边表达式是一个元组,那么右边必须是一个具有同样元素个数的元组。(嵌套元组也是允许的。)右边的值中的每一部分都会被赋值给左边的表达式中的相应部分。例如:
|
||||
|
||||
@ -108,15 +117,15 @@ sum = (try someThrowingFunction()) + anotherThrowingFunction() // 错误:try
|
||||
|
||||
> 赋值运算符语法
|
||||
>
|
||||
<a name="assignment-operator"></a>
|
||||
###### assignment-operator {#assignment-operator}
|
||||
> *赋值运算符* → **=**
|
||||
>
|
||||
|
||||
<a name="ternary_conditional_operator"></a>
|
||||
### 三元条件运算符
|
||||
|
||||
### 三元条件运算符 {#ternary_conditional_operator}
|
||||
*三元条件运算符*会根据条件来对两个给定表达式中的一个进行求值,形式如下:
|
||||
|
||||
> `条件` ? `表达式(条件为真则使用)` : `表达式(条件为假则使用)`
|
||||
>
|
||||
|
||||
如果条件为真,那么对第一个表达式进行求值并返回结果。否则,对第二个表达式进行求值并返回结果。未使用的表达式不会进行求值。
|
||||
|
||||
@ -124,12 +133,11 @@ sum = (try someThrowingFunction()) + anotherThrowingFunction() // 错误:try
|
||||
|
||||
> 三元条件运算符语法
|
||||
>
|
||||
<a name="conditional-operator"></a>
|
||||
###### conditional-operator {#conditional-operator}
|
||||
> *三元条件运算符* → **?** [*表达式*](#expression) **:**
|
||||
>
|
||||
|
||||
<a name="type-casting_operators"></a>
|
||||
### 类型转换运算符
|
||||
|
||||
### 类型转换运算符 {#type-casting_operators}
|
||||
有 4 种类型转换运算符:`is`、`as`、`as? ` 和 `as!`。它们有如下的形式:
|
||||
|
||||
> `表达式` is `类型`
|
||||
@ -139,6 +147,7 @@ sum = (try someThrowingFunction()) + anotherThrowingFunction() // 错误:try
|
||||
> `表达式` as? `类型`
|
||||
>
|
||||
> `表达式` as! `类型`
|
||||
>
|
||||
|
||||
`is` 运算符在运行时检查表达式能否向下转化为指定的类型,如果可以则返回 `ture`,否则返回 `false`。
|
||||
|
||||
@ -159,44 +168,54 @@ f(x as Any)
|
||||
// 打印“Function for Any”
|
||||
```
|
||||
|
||||
桥接可将 Swift 标准库中的类型(例如 `String`)作为一个与之相关的 Foundation 类型(例如 `NSString`)来使用,而不需要新建一个实例。关于桥接的更多信息,请参阅 [*Using Swift with Cocoa and Objective-C (Swift4.1)*](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/BuildingCocoaApps/index.html#//apple_ref/doc/uid/TP40014216) 中的 [Working with Cocoa Data Types](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/BuildingCocoaApps/WorkingWithCocoaDataTypes.html#//apple_ref/doc/uid/TP40014216-CH6)。
|
||||
桥接可将 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!` 运算符执行强制类型转换,返回目标类型的非可选值。如果转换失败,则会导致运行时错误。表达式 `x as! T` 效果等同于 `(x as? T)!`。
|
||||
|
||||
关于类型转换的更多内容和例子,请参阅 [类型转换](../chapter2/19_Type_Casting.md)。
|
||||
关于类型转换的更多内容和例子,请参阅 [类型转换](../chapter2/18_Type_Casting.md)。
|
||||
|
||||
<a name="type-casting-operator"></a>
|
||||
###### type-casting-operator {#type-casting-operator}
|
||||
> 类型转换运算符语法
|
||||
>
|
||||
> *类型转换运算符* → **is** [*类型*](03_Types.md#type)
|
||||
> *类型转换运算符* → **as** [*类型*](03_Types.md#type)
|
||||
> *类型转换运算符* → **as** **?** [*类型*](03_Types.md#type)
|
||||
> *类型转换运算符* → **as** **!** [*类型*](03_Types.md#type)
|
||||
|
||||
<a name="primary_expressions"></a>
|
||||
## 基本表达式
|
||||
> *类型转换运算符* → **is** [*类型*](./03_Types.md#type)
|
||||
>
|
||||
> *类型转换运算符* → **as** [*类型*](./03_Types.md#type)
|
||||
>
|
||||
> *类型转换运算符* → **as** **?** [*类型*](./03_Types.md#type)
|
||||
>
|
||||
> *类型转换运算符* → **as** **!** [*类型*](./03_Types.md#type)
|
||||
>
|
||||
|
||||
## 基本表达式 {#primary_expressions}
|
||||
*基本表达式*是最基本的表达式。它们可以单独使用,也可以跟前缀表达式、二元表达式、后缀表达式组合使用。
|
||||
|
||||
> 基本表达式语法
|
||||
>
|
||||
<a name="primary-expression"></a>
|
||||
> *基本表达式* → [*标识符*](02_Lexical_Structure.md#identifier) [*泛型实参子句*](08_Generic_Parameters_and_Arguments.md#generic-argument-clause)<sub>可选</sub>
|
||||
###### primary-expression {#primary-expression}
|
||||
> *基本表达式* → [*标识符*](./02_Lexical_Structure.md#identifier) [*泛型实参子句*](./09_Generic_Parameters_and_Arguments.md#generic-argument-clause)<sub>可选</sub>
|
||||
>
|
||||
> *基本表达式* → [*字面量表达式*](#literal-expression)
|
||||
>
|
||||
> *基本表达式* → [*self 表达式*](#self-expression)
|
||||
>
|
||||
> *基本表达式* → [*父类表达式*](#superclass-expression)
|
||||
>
|
||||
> *基本表达式* → [*闭包表达式*](#closure-expression)
|
||||
>
|
||||
> *基本表达式* → [*圆括号表达式*](#parenthesized-expression)
|
||||
>
|
||||
> *基本表达式* → [*隐式成员表达式*](#implicit-member-expression)
|
||||
>
|
||||
> *基本表达式* → [*通配符表达式*](#wildcard-expression)
|
||||
>
|
||||
> *基本表达式* → [*选择器表达式*](#selector-expression)
|
||||
>
|
||||
> *基本表达式* → [*key-path字符串表达式*](#key-patch-string-expression)
|
||||
>
|
||||
|
||||
<a name="literal_expression"></a>
|
||||
### 字面量表达式
|
||||
|
||||
### 字面量表达式 {#literal_expression}
|
||||
*字面量表达式*可由普通字面量(例如字符串或者数字),字典或者数组字面量,或者下面列表中的特殊字面量组成:
|
||||
|
||||
字面量 | 类型 | 值
|
||||
@ -224,6 +243,7 @@ myFunction() // 打印“myFunction()”
|
||||
数组字面量是值的有序集合,形式如下:
|
||||
|
||||
> [`值 1`, `值 2`, `...`]
|
||||
>
|
||||
|
||||
数组中的最后一个表达式可以紧跟一个逗号。数组字面量的类型是 `[T]`,这个 `T` 就是数组中元素的类型。如果数组中包含多种类型,`T` 则是跟这些类型最近的的公共父类型。空数组字面量由一组方括号定义,可用来创建特定类型的空数组。
|
||||
|
||||
@ -234,6 +254,7 @@ var emptyArray: [Double] = []
|
||||
字典字面量是一个包含无序键值对的集合,形式如下:
|
||||
|
||||
> [`键 1` : `值 1`, `键 2` : `值 2`, `...`]
|
||||
>
|
||||
|
||||
字典中的最后一个表达式可以紧跟一个逗号。字典字面量的类型是 `[Key : Value]`,`Key` 表示键的类型,`Value` 表示值的类型。如果字典中包含多种类型,那么 `Key` 表示的类型则为所有键最接近的公共父类型,`Value` 与之相似。一个空的字典字面量由方括号中加一个冒号组成(`[:]`),从而与空数组字面量区分开,可以使用空字典字面量来创建特定类型的字典。
|
||||
|
||||
@ -246,40 +267,66 @@ Xcode 使用 playground 字面量对程序编辑器中的颜色、文件或者
|
||||
更多关于在 Xcode 中使用 playground 字面量的信息,请参阅 [添加颜色、文件或图片字面量](https://help.apple.com/xcode/mac/current/#/dev4c60242fc)
|
||||
|
||||
> 字面量表达式语法
|
||||
>
|
||||
>
|
||||
> <a name="literal-expression"></a>
|
||||
> *字面量表达式* → [*字面量*](02_Lexical_Structure.md#literal)
|
||||
> ###### literal-expression {#literal-expression}
|
||||
>
|
||||
> *字面量表达式* → [*字面量*](./02_Lexical_Structure.md#literal)
|
||||
>
|
||||
> *字面量表达式* → [*数组字面量*](#array-literal) | [*字典字面量*](#dictionary-literal) | [*练习场字面量*](#playground-literal)
|
||||
>
|
||||
> *字面量表达式* → **#file** | **#line** | **#column** | **#function**
|
||||
>
|
||||
|
||||
|
||||
> <a name="array-literal"></a>
|
||||
> ###### array-literal {#array-literal}
|
||||
>
|
||||
> *数组字面量* → [[*数组字面量项列表*](#array-literal-items)<sub>可选</sub> **]**
|
||||
> <a name="array-literal-items"></a>
|
||||
>
|
||||
> ###### array-literal-items {#array-literal-items}
|
||||
>
|
||||
> *数组字面量项列表* → [*数组字面量项*](#array-literal-item) **,**<sub>可选</sub> | [*数组字面量项*](#array-literal-item) **,** [*数组字面量项列表*](#array-literal-items)
|
||||
> <a name="array-literal-item"></a>
|
||||
>
|
||||
> ###### array-literal-item {#array-literal-item}
|
||||
>
|
||||
> *数组字面量项* → [*表达式*](#expression)
|
||||
>
|
||||
>
|
||||
> <a name="dictionary-literal"></a>
|
||||
> ###### dictionary-literal {#dictionary-literal}
|
||||
>
|
||||
> *字典字面量* → [[*字典字面量项列表*](#dictionary-literal-items) **]** | **[** **:** **]**
|
||||
> <a name="dictionary-literal-items"></a>
|
||||
>
|
||||
> ###### dictionary-literal-items {#dictionary-literal-items}
|
||||
>
|
||||
> *字典字面量项列表* → [*字典字面量项*](#dictionary-literal-item) **,**<sub>可选</sub> | [*字典字面量项*](#dictionary-literal-item) **,** [*字典字面量项列表*](#dictionary-literal-items)
|
||||
> <a name="dictionary-literal-item"></a>
|
||||
>
|
||||
> ###### dictionary-literal-item {#dictionary-literal-item}
|
||||
>
|
||||
> *字典字面量项* → [*表达式*](#expression) **:** [*表达式*](#expression)。
|
||||
> <a name="playground-literal"></a>
|
||||
>
|
||||
> ###### playground-literal {#playground-literal}
|
||||
>
|
||||
> *playground 字面量* → **#colorLiteral ( red : [*表达式*](#expression) , green :[*表达式*](#expression) [*表达式*](#e[*表达式*](#expression) xpression) , blue :[*表达式*](#expression) , alpha : [*表达式*](#expression) )**
|
||||
>
|
||||
> *playground 字面量* → **#fileLiteral ( resourceName : [*表达式*](#expression) )**
|
||||
> playground 字面量* → **#imageLiteral ( resourceName : [*表达式*](#expression) )**<a name="self_expression"></a>
|
||||
>
|
||||
> ###### playground 字面量* → **#imageLiteral ( resourceName : [*表达式*](#expression) )**self_expression {#self_expression}
|
||||
>
|
||||
|
||||
### Self 表达式
|
||||
|
||||
`self` 表达式是对当前类型或者当前实例的显式引用,它有如下形式:
|
||||
|
||||
> self
|
||||
>
|
||||
> self.`成员名称`
|
||||
>
|
||||
> self[`下标索引`]
|
||||
>
|
||||
> self(`构造器参数`)
|
||||
>
|
||||
> self.init(`构造器参数`)
|
||||
>
|
||||
|
||||
如果在构造器、下标、实例方法中,`self` 引用的是当前类型的实例。在一个类型方法中,`self` 引用的是当前的类型。
|
||||
|
||||
@ -307,24 +354,29 @@ struct Point {
|
||||
|
||||
> Self 表达式语法
|
||||
>
|
||||
<a name="self-expression"></a>
|
||||
###### self-expression {#self-expression}
|
||||
> *self 表达式* → **self** | [*self 方法表达式*](#self-method-expression) | [*self 下标表达式*](#self-subscript-expression) | [*self 构造器表达式*](#self-initializer-expression)
|
||||
>
|
||||
>
|
||||
<a name="self-method-expression"></a>
|
||||
> *self 方法表达式* → **self** **.** [*标识符*](02_Lexical_Structure.md#identifier)
|
||||
<a name="self-subscript-expression"></a>
|
||||
###### self-method-expression {#self-method-expression}
|
||||
> *self 方法表达式* → **self** **.** [*标识符*](./02_Lexical_Structure.md#identifier)
|
||||
>
|
||||
###### self-subscript-expression {#self-subscript-expression}
|
||||
> *self 下标表达式* → **self** **[** [*函数调用参数表*](#function-call-argument-list) **]**
|
||||
<a name="self-initializer-expression"></a>
|
||||
>
|
||||
###### self-initializer-expression {#self-initializer-expression}
|
||||
> *self 构造器表达式* → **self** **.** **init**
|
||||
>
|
||||
|
||||
<a name="superclass_expression"></a>
|
||||
### 父类表达式
|
||||
|
||||
### 父类表达式 {#superclass_expression}
|
||||
*父类*表达式可以使我们在某个类中访问它的父类,它有如下形式:
|
||||
|
||||
> super.`成员名称`
|
||||
>
|
||||
> super[`下标索引`]
|
||||
>
|
||||
> super.init(`构造器参数`)
|
||||
>
|
||||
|
||||
第一种形式用来访问父类的某个成员,第二种形式用来访问父类的下标,第三种形式用来访问父类的构造器。
|
||||
|
||||
@ -332,28 +384,30 @@ struct Point {
|
||||
|
||||
> 父类表达式语法
|
||||
>
|
||||
<a name="superclass-expression"></a>
|
||||
###### superclass-expression {#superclass-expression}
|
||||
> *父类表达式* → [*父类方法表达式*](#superclass-method-expression) | [*父类下标表达式*](#superclass-subscript-expression) | [*父类构造器表达式*](#superclass-initializer-expression)
|
||||
>
|
||||
<a name="superclass-method-expression"></a>
|
||||
> *父类方法表达式* → **super** **.** [*标识符*](02_Lexical_Structure.md#identifier)
|
||||
<a name="superclass-subscript-expression"></a>
|
||||
###### superclass-method-expression {#superclass-method-expression}
|
||||
> *父类方法表达式* → **super** **.** [*标识符*](./02_Lexical_Structure.md#identifier)
|
||||
>
|
||||
###### superclass-subscript-expression {#superclass-subscript-expression}
|
||||
> *父类下标表达式* → **super** [[*函数调用参数表*](#function-call-argument-list) **]**
|
||||
<a name="superclass-initializer-expression"></a>
|
||||
>
|
||||
###### superclass-initializer-expression {#superclass-initializer-expression}
|
||||
> *父类构造器表达式* → **super** **.** **init**
|
||||
>
|
||||
|
||||
<a name="closure_expression"></a>
|
||||
### 闭包表达式
|
||||
|
||||
### 闭包表达式 {#closure_expression}
|
||||
*闭包表达式*会创建一个闭包,在其他语言中也叫 *lambda* 或*匿名*函数。跟函数一样,闭包包含了待执行的代码,不同的是闭包还会捕获所在环境中的常量和变量。它的形式如下:
|
||||
|
||||
```swift
|
||||
{ (parameters) -> return type in
|
||||
>
|
||||
statements
|
||||
}
|
||||
```
|
||||
|
||||
闭包的参数声明形式跟函数一样,请参阅 [函数声明](05_Declarations.html#function_declaration)。
|
||||
闭包的参数声明形式跟函数一样,请参阅 [函数声明](./06_Declarations.md#function_declaration)。
|
||||
|
||||
闭包还有几种特殊的形式,能让闭包使用起来更加简洁:
|
||||
|
||||
@ -366,6 +420,7 @@ struct Point {
|
||||
```swift
|
||||
myFunction {
|
||||
(x: Int, y: Int) -> Int in
|
||||
>
|
||||
return x + y
|
||||
}
|
||||
|
||||
@ -383,12 +438,9 @@ myFunction { $0 + $1 }
|
||||
|
||||
使用闭包表达式时,可以不必将其存储在一个变量或常量中,例如作为函数调用的一部分来立即使用一个闭包。在上面的例子中,传入 `myFunction` 的闭包表达式就是这种立即使用类型的闭包。因此,一个闭包是否逃逸与其使用时的上下文相关。一个会被立即调用或者作为函数的非逃逸参数传递的闭包表达式是非逃逸的,否则,这个闭包表达式是逃逸的。
|
||||
|
||||
关于逃逸闭包的内容,请参阅[逃逸闭包](./chapter2/07_Closures.html#escaping_closures)
|
||||
|
||||
<a name="capture-lists"></a>
|
||||
|
||||
## 捕获列表
|
||||
关于逃逸闭包的内容,请参阅[逃逸闭包](./chapter2/07_Closures.md#escaping_closures)
|
||||
|
||||
## 捕获列表 {#capture-lists}
|
||||
默认情况下,闭包会捕获附近作用域中的常量和变量,并使用强引用指向它们。你可以通过一个*捕获列表*来显式指定它的捕获行为。
|
||||
|
||||
捕获列表在参数列表之前,由中括号括起来,里面是由逗号分隔的一系列表达式。一旦使用了捕获列表,就必须使用 `in` 关键字,即使省略了参数名、参数类型和返回类型。
|
||||
@ -444,37 +496,53 @@ myFunction { [unowned self] in print(self.title) } // 无主引用捕获
|
||||
myFunction { [weak parent = self.parent] in print(parent!.title) }
|
||||
```
|
||||
|
||||
关于闭包表达式的更多信息和例子,请参阅 [闭包表达式](../chapter2/07_Closures.html#closure_expressions)。关于捕获列表的更多信息和例子,请参阅 [解决闭包引起的循环强引用](../chapter2/23_Automatic_Reference_Counting.html#resolving_strong_reference_cycles_for_closures)。
|
||||
关于闭包表达式的更多信息和例子,请参阅 [闭包表达式](../chapter2/07_Closures.md#closure_expressions)。关于捕获列表的更多信息和例子,请参阅 [解决闭包引起的循环强引用](../chapter2/23_Automatic_Reference_Counting.md#resolving_strong_reference_cycles_for_closures)。
|
||||
|
||||
> 闭包表达式语法
|
||||
>
|
||||
>
|
||||
> <a name="closure-expression"></a>
|
||||
> ###### closure-expression {#closure-expression}
|
||||
>
|
||||
> *闭包表达式* → **{** [*闭包签名*](#closure-signature)<sub>可选</sub> [*语句*](#statements) **}**
|
||||
>
|
||||
>
|
||||
> <a name="closure-signature"></a>
|
||||
> ###### closure-signature {#closure-signature}
|
||||
>
|
||||
>
|
||||
> 闭包签名* → [*参数子句*](#parameter-clause) [*函数结果*](05_Declarations.html#function-result)<sub>可选</sub> **in**
|
||||
> 闭包签名* → [*参数子句*](#parameter-clause) [*函数结果*](05_Declarations.md#function-result)<sub>可选</sub> **in**
|
||||
>
|
||||
> *闭包签名* → [*标识符列表*](#identifier-list) [*函数结果*](05_Declarations.md#function-result)<sub>可选</sub> **in**
|
||||
> *闭包签名* → [*捕获列表*](#capture-list) [*参数子句*](05_Declarations.md#parameter-clause) [*函数结果*](05_Declarations.md#function-result)<sub>可选</sub> **in**
|
||||
> *闭包签名* → [*捕获列表*](#capture-list) [*标识符列表*](02_Lexical_Structure.md#identifier-list) [*函数结果*](05_Declarations.md#function-result)<sub>可选</sub> **in**
|
||||
>
|
||||
> *闭包签名* → [*捕获列表*](#capture-list) [*参数子句*](05_Declarations.md#parameter-clause) [*函数结果*](./06_Declarations.md#function-result)<sub>可选</sub> **in**
|
||||
>
|
||||
> *闭包签名* → [*捕获列表*](#capture-list) [*标识符列表*](02_Lexical_Structure.md#identifier-list) [*函数结果*](./06_Declarations.md#function-result)<sub>可选</sub> **in**
|
||||
>
|
||||
> *闭包签名* → [*捕获列表*](#capture-list) **in**
|
||||
>
|
||||
>
|
||||
> <a name="capture-list"></a>
|
||||
> ###### capture-list {#capture-list}
|
||||
>
|
||||
>
|
||||
> 捕获列表* → [ [*捕获列表项列表*](#capture-list-items) **]**
|
||||
> <a name="capture-list-items"></a>
|
||||
>
|
||||
> ###### capture-list-items {#capture-list-items}
|
||||
>
|
||||
> *捕获列表项列表* → [*捕获列表项*](#capture-list-item) | [*捕获列表项*](#capture-list-item) **,** [*捕获列表项列表*](#capture-list-items)
|
||||
> <a name="capture-list-item"></a>
|
||||
>
|
||||
> ###### capture-list-item {#capture-list-item}
|
||||
>
|
||||
> *捕获列表项* → [*捕获说明符*](#capture-specifier)<sub>可选</sub> [*表达式*](#expression)
|
||||
> <a name="capture-specifier"></a>
|
||||
>
|
||||
> ###### capture-specifier {#capture-specifier}
|
||||
>
|
||||
> *捕获说明符* → **weak** | **unowned** | **unowned(safe)** | **unowned(unsafe)**
|
||||
>
|
||||
|
||||
<a name="implicit_member_expression"></a>
|
||||
### 隐式成员表达式
|
||||
|
||||
### 隐式成员表达式 {#implicit_member_expression}
|
||||
若类型可被推断出来,可以使用*隐式成员表达式*来访问某个类型的成员(例如某个枚举成员或某个类型方法),形式如下:
|
||||
|
||||
> .`成员名称`
|
||||
>
|
||||
|
||||
例如:
|
||||
|
||||
@ -485,46 +553,47 @@ x = .AnotherValue
|
||||
|
||||
> 隐式成员表达式语法
|
||||
>
|
||||
<a name="implicit-member-expression"></a>
|
||||
> *隐式成员表达式* → **.** [*标识符*](02_Lexical_Structure.md#identifier)
|
||||
|
||||
<a name="parenthesized_expression"></a>
|
||||
### 圆括号表达式
|
||||
###### implicit-member-expression {#implicit-member-expression}
|
||||
> *隐式成员表达式* → **.** [*标识符*](./02_Lexical_Structure.md#identifier)
|
||||
>
|
||||
|
||||
### 圆括号表达式 {#parenthesized_expression}
|
||||
*圆括号表达式*是由圆括号包围的表达式。你可以用圆括号说明成组的表达式的先后操作。成组的圆括号不会改变表达式的类型 - 例如 `(1)` 的类型就是简单的 `Int`。
|
||||
|
||||
> 圆括号表达式语法
|
||||
>
|
||||
<a name="parenthesized-expression"></a>
|
||||
###### parenthesized-expression {#parenthesized-expression}
|
||||
> *圆括号表达式* → **( [*表达式*](#expression) )**
|
||||
>
|
||||
|
||||
<a name="Tuple_Expression"></a>
|
||||
### 元组表达式
|
||||
|
||||
### 元组表达式 {#Tuple_Expression}
|
||||
*元组表达式*由圆括号和其中多个逗号分隔的子表达式组成。每个子表达式前面可以有一个标识符,用冒号隔开。元组表达式形式如下:
|
||||
|
||||
> (`标识符 1` : `表达式 1`, `标识符 2` : `表达式 2`, `...`)
|
||||
>
|
||||
|
||||
元组表达式可以一个表达式都没有,也可以包含两个或是更多的表达式。单个表达式用括号括起来就是括号表达式了。
|
||||
|
||||
> 注意
|
||||
>
|
||||
>
|
||||
> 在 Swift 中,空的元组表达式和空的元组类型都写作 `()`。由于 `Void` 是 `()` 的类型别名,因此可以使用它来表示空的元组类型。虽然如此,`Void` 就像所有的类型别名一样,永远是一个类型——不能表示空的元组表达式。
|
||||
>
|
||||
|
||||
|
||||
> 元组表达式语法
|
||||
>
|
||||
<a name="tuple-expression"></a>
|
||||
###### tuple-expression {#tuple-expression}
|
||||
> *元组表达式* → **( )** | **(**[*元组元素*](#tuple-element), [*元组元素列表*](#tuple-element-list) **)**
|
||||
<a name="tuple-element-list"></a>
|
||||
>
|
||||
###### tuple-element-list {#tuple-element-list}
|
||||
> *元组元素列表* → [*元组元素*](#tuple-element) | [*元组元素*](#tuple-element) **,** [*元组元素列表*](#tuple-element-list)
|
||||
<a name="tuple-element"></a>
|
||||
>
|
||||
###### tuple-element {#tuple-element}
|
||||
> *元组元素* → [*表达式*](#expression) | [*标识符*](identifier) **:** [*表达式*](#expression)
|
||||
>
|
||||
|
||||
<a name="wildcard_expression"></a>
|
||||
|
||||
### 通配符表达式
|
||||
|
||||
### 通配符表达式 {#wildcard_expression}
|
||||
*通配符表达式*可以在赋值过程中显式忽略某个值。例如下面的代码中,`10` 被赋值给 `x`,而 `20` 则被忽略:
|
||||
|
||||
```swift
|
||||
@ -534,16 +603,16 @@ x = .AnotherValue
|
||||
|
||||
> 通配符表达式语法
|
||||
>
|
||||
<a name="wildcard-expression"></a>
|
||||
###### wildcard-expression {#wildcard-expression}
|
||||
> *通配符表达式* → **_**
|
||||
>
|
||||
|
||||
|
||||
<a name="key-path_expression"></a>
|
||||
### Key-path 表达式
|
||||
|
||||
### Key-path 表达式 {#key-path_expression}
|
||||
Key-path 表达式引用一个类型的属性或下标。在动态语言中使场景可以使用 Key-path 表达式,例如观察键值对。格式为:
|
||||
|
||||
> **\类型名.路径**
|
||||
>
|
||||
|
||||
*类型名*是一个具体类型的名称,包含任何泛型参数,例如 `String`、`[Int]` 或 `Set<Int>`。
|
||||
|
||||
@ -620,6 +689,7 @@ let myGreeting = greetings[keyPath: \[String].[1]]
|
||||
var index = 2
|
||||
let path = \[String].[index]
|
||||
let fn: ([String]) -> String = { strings in strings[index] }
|
||||
>
|
||||
|
||||
print(greetings[keyPath: path])
|
||||
// 打印 "bonjour"
|
||||
@ -665,30 +735,37 @@ print(interestingNumbers[keyPath: \[String: [Int]].["hexagonal"]!.count.bitWidth
|
||||
// 打印 "64"
|
||||
```
|
||||
|
||||
关于更多如何使用 key path 与 Objective-C APIs 交互的信息,请参阅 [在 Swift 中使用 Objective-C 运行时特性](https://developer.apple.com/documentation/swift/using_objective_c_runtime_features_in_swift)。关于更多 key-value 编程和 key-value 观察的信息,请参阅 [Key-Value 编程](https://developer.apple.com/library/content/documentation/Cocoa/Conceptual/KeyValueCoding/index.html#//apple_ref/doc/uid/10000107i) 和 [Key-Value 观察编程](https://developer.apple.com/library/content/documentation/Cocoa/Conceptual/KeyValueObserving/KeyValueObserving.html#//apple_ref/doc/uid/10000177i)
|
||||
关于更多如何使用 key path 与 Objective-C APIs 交互的信息,请参阅 [在 Swift 中使用 Objective-C 运行时特性](./https://developer.apple.com/documentation/swift/using_objective_c_runtime_features_in_swift)。关于更多 key-value 编程和 key-value 观察的信息,请参阅 [Key-Value 编程](https://developer.apple.com/library/content/documentation/Cocoa/Conceptual/KeyValueCoding/index.md#//apple_ref/doc/uid/10000107i) 和 [Key-Value 观察编程](./https://developer.apple.com/library/content/documentation/Cocoa/Conceptual/KeyValueObserving/KeyValueObserving.md#//apple_ref/doc/uid/10000177i)
|
||||
|
||||
> key-path 表达式语法
|
||||
>
|
||||
>
|
||||
> <a name="key-path-expression"></a>
|
||||
> *key-path 表达式* → **\\** [类型](03_Types.md#type)<sub>可选</sub> **.** [多个 key-path 组件](#key-path-components)
|
||||
> <a name="key-path-components"></a>
|
||||
> ###### key-path-expression {#key-path-expression}
|
||||
>
|
||||
> *key-path 表达式* → **\\** [类型](./03_Types.md#type)<sub>可选</sub> **.** [多个 key-path 组件](#key-path-components)
|
||||
>
|
||||
> ###### key-path-components {#key-path-components}
|
||||
>
|
||||
> *多个 key-path 组件* → [key-path 组件](#key-path-component) | [key-path 组件](#key-path-component) **.** [多个 key-path 组件](#key-path-components)
|
||||
> <a name="key-path-component"></a>
|
||||
> *key-path 组件* → [标识符](02_Lexical_Structure.html#identifier) [多个 key-path 后缀](#key-path-postfixes)<sub>可选<sub> | [多个 key-path 后缀](#key-path-postfixes)
|
||||
> <a name="key-path-postfixes"></a>
|
||||
> *多个 key-path 后缀* → [key-path 后缀](#key-path-postfix) [多个 key-path 后缀](#key-path-postfixes)<sub>可选<sub>
|
||||
> <a name="key-path-postfixes"></a>
|
||||
>
|
||||
> ###### key-path-component {#key-path-component}
|
||||
>
|
||||
> *key-path 组件* → [标识符](./02_Lexical_Structure.md#identifier) [多个 key-path 后缀](#key-path-postfixes)<sub>可选<sub> | [多个 key-path 后缀](#key-path-postfixes)
|
||||
>
|
||||
> ###### key-path-postfixes {#key-path-postfixes}
|
||||
>
|
||||
> ###### *多个 key-path 后缀* → [key-path 后缀](#key-path-postfix) [多个 key-path 后缀](#key-path-postfixes)<sub>可选<sub> key-path-postfixes {#key-path-postfixes}
|
||||
>
|
||||
> *key-path 后缀* → **?** | **!** | **self** | **\[** [函数调用参数表](#function-call-argument-list) **\]**
|
||||
>
|
||||
|
||||
|
||||
|
||||
<a name="selector_expression"></a>
|
||||
|
||||
### 选择器表达式
|
||||
|
||||
### 选择器表达式 {#selector_expression}
|
||||
*选择器表达式*可以让你通过选择器来引用在 Objective-C 中方法(method)和属性(property)的 setter 和 getter 方法。
|
||||
|
||||
> \#selector(方法名)
|
||||
>
|
||||
\#selector(getter: 属性名)
|
||||
\#selector(setter: 属性名)
|
||||
|
||||
@ -718,6 +795,7 @@ extension SomeClass {
|
||||
func doSomething(_ x: String) { }
|
||||
}
|
||||
let anotherSelector = #selector(SomeClass.doSomething(_:) as (SomeClass) -> (String) -> Void)
|
||||
>
|
||||
```
|
||||
|
||||
由于选择器是在编译时创建的,因此编译器可以检查方法或者属性是否存在,以及是否在运行时暴露给了 Objective-C 。
|
||||
@ -725,22 +803,25 @@ let anotherSelector = #selector(SomeClass.doSomething(_:) as (SomeClass) -> (Str
|
||||
> 注意
|
||||
>
|
||||
> 虽然方法名或者属性名是个表达式,但是它不会被求值。
|
||||
>
|
||||
|
||||
更多关于如何在 Swift 代码中使用选择器来与 Objective-C API 进行交互的信息,请参阅 [在 Swift 中使用 Objective-C 运行时特性](https://developer.apple.com/documentation/swift/using_objective_c_runtime_features_in_swift)。
|
||||
|
||||
> 选择器表达式语法
|
||||
<a name="selector-expression"></a>
|
||||
>
|
||||
###### selector-expression {#selector-expression}
|
||||
> *选择器表达式* → __#selector__ **(** [*表达式*](#expression) **)**
|
||||
>
|
||||
> *选择器表达式* → __#selector__ **(** [*getter:表达式*](#expression) **)**
|
||||
>
|
||||
> *选择器表达式* → __#selector__ **(** [*setter:表达式*](#expression) **)**
|
||||
>
|
||||
|
||||
<a name="key-path_string_expressions"></a>
|
||||
|
||||
## Key-path 字符串表达式
|
||||
|
||||
## Key-path 字符串表达式 {#key-path_string_expressions}
|
||||
key-path 字符串表达式可以访问一个引用 Objective-C 属性的字符串,通常在 key-value 编程和 key-value 观察 APIs 中使用。其格式如下:
|
||||
|
||||
> `#keyPath` ( `属性名` )
|
||||
>
|
||||
|
||||
属性名必须是一个可以在 Objective-C 运行时使用的属性的引用。在编译期,key-path 字符串表达式会被一个字符串字面量替换。例如:
|
||||
|
||||
@ -766,6 +847,7 @@ if let value = c.value(forKey: keyPath) {
|
||||
```swift
|
||||
extension SomeClass {
|
||||
func getSomeKeyPath() -> String {
|
||||
>
|
||||
return #keyPath(someProperty)
|
||||
}
|
||||
}
|
||||
@ -775,51 +857,64 @@ print(keyPath == c.getSomeKeyPath())
|
||||
|
||||
由于 key-path 字符串表达式在编译期才创建,编译期可以检查属性是否存在,以及属性是否暴露给 Objective-C 运行时。
|
||||
|
||||
关于更多如何使用 key path 与 Objective-C APIs 交互的信息,请参阅 [在 Swift 中使用 Objective-C 运行时特性](https://developer.apple.com/documentation/swift/using_objective_c_runtime_features_in_swift)。关于更多 key-value 编程和 key-value 观察的信息,请参阅 [Key-Value 编程](https://developer.apple.com/library/content/documentation/Cocoa/Conceptual/KeyValueCoding/index.html#//apple_ref/doc/uid/10000107i) 和 [Key-Value 观察编程](https://developer.apple.com/library/content/documentation/Cocoa/Conceptual/KeyValueObserving/KeyValueObserving.html#//apple_ref/doc/uid/10000177i)
|
||||
关于更多如何使用 key path 与 Objective-C APIs 交互的信息,请参阅 [在 Swift 中使用 Objective-C 运行时特性](./https://developer.apple.com/documentation/swift/using_objective_c_runtime_features_in_swift)。关于更多 key-value 编程和 key-value 观察的信息,请参阅 [Key-Value 编程](https://developer.apple.com/library/content/documentation/Cocoa/Conceptual/KeyValueCoding/index.md#//apple_ref/doc/uid/10000107i) 和 [Key-Value 观察编程](./https://developer.apple.com/library/content/documentation/Cocoa/Conceptual/KeyValueObserving/KeyValueObserving.md#//apple_ref/doc/uid/10000177i)
|
||||
|
||||
> 注意
|
||||
>
|
||||
>
|
||||
> 尽管*属性名*是一个表达式,但它永远不会被求值
|
||||
>
|
||||
|
||||
> key-path 字符串表达式语法
|
||||
> <a name="key-path-string-expression"></a>
|
||||
>
|
||||
> ###### key-path-string-expression {#key-path-string-expression}
|
||||
>
|
||||
> *key-path 字符串表达式* → **#keyPath (** [表达式](#expression) **)**
|
||||
>
|
||||
|
||||
<a name="postfix_expressions"></a>
|
||||
|
||||
## 后缀表达式
|
||||
|
||||
## 后缀表达式 {#postfix_expressions}
|
||||
*后缀表达式*就是在某个表达式的后面运用后缀运算符或其他后缀语法。从语法构成上来看,基本表达式也是后缀表达式。
|
||||
|
||||
关于这些运算符的更多信息,请参阅 [基本运算符](../chapter2/02_Basic_Operators.html) 和 [高级运算符](../chapter2/26_Advanced_Operators.html)。
|
||||
关于这些运算符的更多信息,请参阅 [基本运算符](../chapter2/02_Basic_Operators.md) 和 [高级运算符](../chapter2/26_Advanced_Operators.md)。
|
||||
|
||||
关于 Swift 标准库提供的运算符的更多信息,请参阅 [运算符定义](https://developer.apple.com/documentation/swift/operator_declarations)。
|
||||
|
||||
> 后缀表达式语法
|
||||
<a name="postfix-expression"></a>
|
||||
>
|
||||
###### postfix-expression {#postfix-expression}
|
||||
> *后缀表达式* → [*基本表达式*](#primary-expression)
|
||||
>
|
||||
> *后缀表达式* → [*后缀表达式*](#postfix-expression) [*后缀运算符*](02_Lexical_Structure.md#postfix-operator)
|
||||
>
|
||||
> *后缀表达式* → [*函数调用表达式*](#function-call-expression)
|
||||
>
|
||||
> *后缀表达式* → [*构造器表达式*](#initializer-expression)
|
||||
>
|
||||
> *后缀表达式* → [*显式成员表达式*](#explicit-member-expression)
|
||||
>
|
||||
> *后缀表达式* → [*后缀 self 表达式*](#postfix-self-expression)
|
||||
>
|
||||
> *后缀表达式* → [*dynamicType 表达式*](#dynamic-type-expression)
|
||||
>
|
||||
> *后缀表达式* → [*下标表达式*](#subscript-expression)
|
||||
>
|
||||
> *后缀表达式* → [*强制取值表达式*](#forced-value-expression)
|
||||
>
|
||||
> *后缀表达式* → [*可选链表达式*](#optional-chaining-expression)
|
||||
>
|
||||
|
||||
<a name="function_call_expression"></a>
|
||||
### 函数调用表达式
|
||||
|
||||
### 函数调用表达式 {#function_call_expression}
|
||||
*函数调用表达式*由函数名和参数列表组成,形式如下:
|
||||
|
||||
> `函数名`(`参数 1`, `参数 2`)
|
||||
>
|
||||
|
||||
函数名可以是值为函数类型的任意表达式。
|
||||
|
||||
如果函数声明中指定了参数的名字,那么在调用的时候也必须得写出来。这种函数调用表达式具有以下形式:
|
||||
|
||||
> `函数名`(`参数名 1`: `参数 1`, `参数名 2`: `参数 2`)
|
||||
>
|
||||
|
||||
如果函数的最后一个参数是函数类型,可以在函数调用表达式的尾部(右圆括号之后)加上一个闭包,该闭包会作为函数的最后一个参数。如下两种写法是等价的:
|
||||
|
||||
@ -838,27 +933,39 @@ myData.someMethod {$0 == 13}
|
||||
```
|
||||
|
||||
> 函数调用表达式语法
|
||||
> <a name="function-call-expression"></a>
|
||||
>
|
||||
> ###### function-call-expression {#function-call-expression}
|
||||
>
|
||||
> *函数调用表达式* → [*后缀表达式*](#postfix-expression) [*函数调用参数子句*](#function-call-argument-clause)
|
||||
>
|
||||
> *函数调用表达式* → [*后缀表达式*](#postfix-expression) [*函数调用参数子句*](#function-call-argument-clause)<sub>可选</sub> [*尾随闭包*](#trailing-closure)
|
||||
>
|
||||
>
|
||||
> <a name="function-call-argument-clause"></a>
|
||||
> ###### function-call-argument-clause {#function-call-argument-clause}
|
||||
>
|
||||
> *函数调用参数子句* → **(** **)** | **(** [*函数调用参数表*](#function-call-argument-list) **)**
|
||||
> <a name="function-call-argument-list"></a>
|
||||
>
|
||||
> ###### function-call-argument-list {#function-call-argument-list}
|
||||
>
|
||||
> *函数调用参数表* → [函数调用参数](#function-call-argument) | [函数调用参数](#function-call-argument) **,** [*函数调用参数表*](#function-call-argument-list)
|
||||
> <a name="function-call-argument"></a>
|
||||
> *函数调用参数* → [表达式](#expression) | [标识符](02_Lexical_Structure.html#identifier) **:** [*表达式*](#expression)
|
||||
> *函数调用参数* → [运算符](02_Lexical_Structure.html#operator) | [标识符](02_Lexical_Structure.html#identifier) **:** [*运算符*](02_Lexical_Structure.html#operator)
|
||||
>
|
||||
> ###### function-call-argument {#function-call-argument}
|
||||
>
|
||||
> *函数调用参数* → [表达式](#expression) | [标识符](02_Lexical_Structure.md#identifier) **:** [*表达式*](#expression)
|
||||
>
|
||||
> *函数调用参数* → [运算符](./02_Lexical_Structure.md#operator) | [标识符](./02_Lexical_Structure.md#identifier) **:** [*运算符*](./02_Lexical_Structure.md#operator)
|
||||
>
|
||||
>
|
||||
> <a name="trailing-closure"></a>
|
||||
> ###### trailing-closure {#trailing-closure}
|
||||
>
|
||||
> *尾随闭包* → [*闭包表达式*](#closure-expression)
|
||||
>
|
||||
|
||||
<a name="initializer_expression"></a>
|
||||
### 构造器表达式
|
||||
|
||||
### 构造器表达式 {#initializer_expression}
|
||||
*构造器表达式*用于访问某个类型的构造器,形式如下:
|
||||
|
||||
> `表达式`.init(`构造器参数`)
|
||||
>
|
||||
|
||||
你可以在函数调用表达式中使用构造器表达式来初始化某个类型的新实例。也可以使用构造器表达式来代理给父类构造器。
|
||||
|
||||
@ -876,6 +983,7 @@ class SomeSubClass: SomeSuperClass {
|
||||
```swift
|
||||
// 类型注解是必须的,因为 String 类型有多种构造器
|
||||
let initializer: Int -> String = String.init
|
||||
>
|
||||
let oneTwoThree = [1, 2, 3].map(initializer).reduce("", combine: +)
|
||||
print(oneTwoThree)
|
||||
// 打印“123”
|
||||
@ -892,16 +1000,18 @@ let s3 = someValue.dynamicType.init(data: 7) // 有效
|
||||
```
|
||||
|
||||
> 构造器表达式语法
|
||||
<a name="initializer-expression"></a>
|
||||
>
|
||||
###### initializer-expression {#initializer-expression}
|
||||
> *构造器表达式* → [*后缀表达式*](#postfix-expression) **.** **init**
|
||||
>
|
||||
> *构造器表达式* → [*后缀表达式*](#postfix-expression) **.** **init** **(** [*参数名称*](#argument-names) **)**
|
||||
>
|
||||
|
||||
<a name="explicit_member_expression"></a>
|
||||
### 显式成员表达式
|
||||
|
||||
### 显式成员表达式 {#explicit_member_expression}
|
||||
*显式成员表达式*允许我们访问命名类型、元组或者模块的成员,其形式如下:
|
||||
|
||||
> `表达式`.`成员名`
|
||||
>
|
||||
|
||||
命名类型的某个成员在原始实现或者扩展中定义,例如:
|
||||
|
||||
@ -923,7 +1033,7 @@ t.0 = t.1
|
||||
|
||||
对于模块的成员来说,只能直接访问顶级声明中的成员。
|
||||
|
||||
使用 `dynamicMemberLookup` 属性声明的类型包含可以在运行时查找的成员,具体请参阅 [属性](07_Attributes.html)
|
||||
使用 `dynamicMemberLookup` 属性声明的类型包含可以在运行时查找的成员,具体请参阅 [属性](./07_Attributes.md)
|
||||
|
||||
为了区分只有参数名有所不同的方法或构造器,在圆括号中写出参数名,参数名后紧跟一个冒号,对于没有参数名的参数,使用下划线代替参数名。而对于重载方法,则需使用类型标注进行区分。例如:
|
||||
|
||||
@ -942,6 +1052,7 @@ let b = instance.someMethod(_:y:) // 无歧义
|
||||
let d = instance.overloadedMethod // 有歧义
|
||||
let d = instance.overloadedMethod(_:y:) // 有歧义
|
||||
let d: (Int, Bool) -> Void = instance.overloadedMethod(_:y:) // 无歧义
|
||||
>
|
||||
```
|
||||
|
||||
如果点号(`.`)出现在行首,它会被视为显式成员表达式的一部分,而不是隐式成员表达式的一部分。例如如下代码所展示的被分为多行的链式方法调用:
|
||||
@ -950,27 +1061,33 @@ let d: (Int, Bool) -> Void = instance.overloadedMethod(_:y:) // 无歧义
|
||||
let x = [10, 3, 20, 15, 4]
|
||||
.sort()
|
||||
.filter { $0 > 5 }
|
||||
>
|
||||
.map { $0 * 100 }
|
||||
```
|
||||
|
||||
> 显式成员表达式语法
|
||||
<a name="explicit-member-expression"></a>
|
||||
> *显式成员表达式* → [*后缀表达式*](#postfix-expression) **.** [*十进制数字*] (02_Lexical_Structure.html#decimal-digit)
|
||||
> *显式成员表达式* → [*后缀表达式*](#postfix-expression) **.** [*标识符*](02_Lexical_Structure.html#identifier) [*泛型实参子句*](08_Generic_Parameters_and_Arguments.html#generic-argument-clause)<sub>可选</sub><br/>
|
||||
> *显式成员表达式* → [*后缀表达式*](#postfix-expression) **.** [*标识符*] (02_Lexical_Structure.html#identifier) **(** [*参数名称*](#argument-names) **)**
|
||||
>
|
||||
<a name="argument-names"></a>
|
||||
###### explicit-member-expression {#explicit-member-expression}
|
||||
> *显式成员表达式* → [*后缀表达式*](#postfix-expression) **.** [*十进制数字*] (02_Lexical_Structure.md#decimal-digit)
|
||||
>
|
||||
> *显式成员表达式* → [*后缀表达式*](#postfix-expression) **.** [*标识符*](02_Lexical_Structure.md#identifier) [*泛型实参子句*](./09_Generic_Parameters_and_Arguments.md#generic-argument-clause)<sub>可选</sub><br/>
|
||||
>
|
||||
> *显式成员表达式* → [*后缀表达式*](#postfix-expression) **.** [*标识符*] (02_Lexical_Structure.md#identifier) **(** [*参数名称*](#argument-names) **)**
|
||||
>
|
||||
###### argument-names {#argument-names}
|
||||
> *参数名称* → [*参数名*](#argument-name) [*参数名称*](#argument-names)<sub>可选</sub><br/>
|
||||
<a name="argument-name"></a>
|
||||
> *参数名* → [*标识符*](02_Lexical_Structure.html#identifier) **:**
|
||||
|
||||
<a name="postfix_self_expression"></a>
|
||||
### 后缀 self 表达式
|
||||
>
|
||||
###### argument-name {#argument-name}
|
||||
> *参数名* → [*标识符*](./02_Lexical_Structure.md#identifier) **:**
|
||||
>
|
||||
|
||||
### 后缀 self 表达式 {#postfix_self_expression}
|
||||
后缀 `self` 表达式由某个表达式或类型名紧跟 `.self` 组成,其形式如下:
|
||||
|
||||
> `表达式`.self
|
||||
>
|
||||
> `类型`.self
|
||||
>
|
||||
|
||||
第一种形式返回表达式的值。例如:`x.self` 返回 `x`。
|
||||
|
||||
@ -978,32 +1095,32 @@ let x = [10, 3, 20, 15, 4]
|
||||
|
||||
> 后缀 self 表达式语法
|
||||
>
|
||||
<a name="postfix-self-expression"></a>
|
||||
###### postfix-self-expression {#postfix-self-expression}
|
||||
> *后缀 self 表达式* → [*后缀表达式*](#postfix-expression) **.** **self**
|
||||
>
|
||||
|
||||
|
||||
<a name="subscript_expression"></a>
|
||||
### 下标表达式
|
||||
|
||||
### 下标表达式 {#subscript_expression}
|
||||
可通过*下标表达式*访问相应的下标,形式如下:
|
||||
|
||||
> `表达式`[`索引表达式`]
|
||||
>
|
||||
|
||||
要获取下标表达式的值,可将索引表达式作为下标表达式的参数来调用下标 getter。下标 setter 的调用方式与之一样。
|
||||
|
||||
关于下标的声明,请参阅 [协议下标声明](05_Declarations.html#protocol_subscript_declaration)。
|
||||
关于下标的声明,请参阅 [协议下标声明](./06_Declarations.md#protocol_subscript_declaration)。
|
||||
|
||||
> 下标表达式语法
|
||||
>
|
||||
<a name="subscript-expression"></a>
|
||||
###### subscript-expression {#subscript-expression}
|
||||
> *下标表达式* → [*后缀表达式*](#postfix-expression) **[** [*表达式列表*](#expression-list) **]**
|
||||
>
|
||||
|
||||
<a name="forced-Value_expression"></a>
|
||||
### 强制取值表达式
|
||||
|
||||
### 强制取值表达式 {#forced-Value_expression}
|
||||
当你确定可选值不是 `nil` 时,可以使用*强制取值表达式*来强制解包,形式如下:
|
||||
|
||||
> `表达式`!
|
||||
>
|
||||
|
||||
如果该表达式的值不是 `nil`,则返回解包后的值。否则,抛出运行时错误。
|
||||
|
||||
@ -1021,15 +1138,15 @@ someDictionary["a"]![0] = 100
|
||||
|
||||
> 强制取值语法
|
||||
>
|
||||
<a name="forced-value-expression"></a>
|
||||
###### forced-value-expression {#forced-value-expression}
|
||||
> *强制取值表达式* → [*后缀表达式*](#postfix-expression) **!**
|
||||
>
|
||||
|
||||
<a name="optional-chaining_expression"></a>
|
||||
### 可选链表达式
|
||||
|
||||
### 可选链表达式 {#optional-chaining_expression}
|
||||
*可选链表达式*提供了一种使用可选值的便捷方法,形式如下:
|
||||
|
||||
> `表达式`?
|
||||
>
|
||||
|
||||
后缀 `?` 运算符会根据表达式生成可选链表达式而不会改变表达式的值。
|
||||
|
||||
@ -1055,6 +1172,7 @@ if let unwrappedC = c {
|
||||
|
||||
```swift
|
||||
func someFunctionWithSideEffects() -> Int {
|
||||
>
|
||||
// 译者注:为了能看出此函数是否被执行,加上了一句打印
|
||||
print("someFunctionWithSideEffects")
|
||||
return 42
|
||||
@ -1072,5 +1190,6 @@ someDictionary["a"]?[0] = someFunctionWithSideEffects()
|
||||
|
||||
> 可选链表达式语法
|
||||
>
|
||||
<a name="optional-chaining-expression"></a>
|
||||
###### optional-chaining-expression {#optional-chaining-expression}
|
||||
> *可选链表达式* → [*后缀表达式*](#postfix-expression) **?**
|
||||
>
|
||||
|
||||
@ -1,6 +1,4 @@
|
||||
<a name="statement_statements"></a>
|
||||
# 语句(Statements)
|
||||
|
||||
# 语句(Statements) {#statement_statements}
|
||||
在 Swift 中,有三种类型的语句:简单语句、编译器控制语句和控制流语句。简单语句是最常见的,用于构造表达式或者声明。编译器控制语句允许程序改变编译器的行为,包含编译配置语句和行控制语句。
|
||||
|
||||
控制流语句则用于控制程序执行的流程,Swift 中有多种类型的控制流语句:循环语句、分支语句和控制转移语句。循环语句用于重复执行代码块;分支语句用于执行满足特定条件的代码块;控制转移语句则用于改变代码的执行顺序。另外,Swift 提供了 `do` 语句,用于构建局部作用域,还用于错误的捕获和处理;还提供了 `defer` 语句,用于退出当前作用域之前执行清理操作。
|
||||
@ -8,36 +6,47 @@
|
||||
是否将分号(`;`)添加到语句的末尾是可选的。但若要在同一行内写多条独立语句,则必须使用分号。
|
||||
|
||||
> 语句语法
|
||||
<a name="statement"></a>
|
||||
> *语句* → [*表达式*](04_Expressions.md#expression) **;**<sub>可选</sub>
|
||||
> *语句* → [*声明*](05_Declarations.md#declaration) **;**<sub>可选</sub>
|
||||
>
|
||||
###### statement {#statement}
|
||||
> *语句* → [*表达式*](./04_Expressions.md#expression) **;**<sub>可选</sub>
|
||||
>
|
||||
> *语句* → [*声明*](./06_Declarations.md#declaration) **;**<sub>可选</sub>
|
||||
>
|
||||
> *语句* → [*循环语句*](#loop-statement) **;**<sub>可选</sub>
|
||||
>
|
||||
> *语句* → [*分支语句*](#branch-statement) **;**<sub>可选</sub>
|
||||
>
|
||||
> *语句* → [*带标签的语句*](#labeled-statement) **;**<sub>可选</sub>
|
||||
>
|
||||
> *语句* → [*控制转移语句*](#control-transfer-statement) **;**<sub>可选</sub>
|
||||
>
|
||||
> *语句* → [*defer 语句*](#defer-statement) **;**<sub>可选</sub>
|
||||
>
|
||||
> *语句* → [*do 语句*](#do-statement) **:**<sub>可选</sub>
|
||||
>
|
||||
> *语句* → [*编译器控制语句*](#compiler-control-statement)
|
||||
<a name="statements"></a>
|
||||
>
|
||||
###### statements {#statements}
|
||||
> *多条语句* → [*语句*](#statement) [*多条语句*](#statements)<sub>可选</sub>
|
||||
>
|
||||
|
||||
<a name="loop_statements"></a>
|
||||
## 循环语句
|
||||
|
||||
## 循环语句 {#loop_statements}
|
||||
循环语句会根据特定的循环条件来重复执行代码块。Swift 提供三种类型的循环语句:`for-in` 语句、`while` 语句和 `repeat-while` 语句。
|
||||
|
||||
通过 `break` 语句和 `continue` 语句可以改变循环语句的控制流。有关这两条语句,详情参见 [Break 语句](#break_statement) 和 [Continue 语句](#continue_statement)。
|
||||
|
||||
> 循环语句语法
|
||||
>
|
||||
>
|
||||
<a name="loop-statement"></a>
|
||||
###### loop-statement {#loop-statement}
|
||||
> *循环语句* → [*for-in 语句*](#for-in-statement)
|
||||
>
|
||||
> *循环语句* → [*while 语句*](#while-statement)
|
||||
>
|
||||
> *循环语句* → [*repeat-while 语句*](#repeat-while-statement)
|
||||
>
|
||||
|
||||
<a name="for-in_statements"></a>
|
||||
### For-In 语句
|
||||
|
||||
### For-In 语句 {#for-in_statements}
|
||||
`for-in` 语句会为集合(或实现了 `SequenceType` 协议的任意类型)中的每一项执行一次代码块。
|
||||
|
||||
`for-in` 语句的形式如下:
|
||||
@ -51,13 +60,13 @@ for item in collection {
|
||||
`for-in` 语句在循环开始前会调用集合表达式(`collection expression`)的 `makeIterator()` 方法来获取一个实现了 `IteratorProtocol` 协议的迭代器类型。接下来循环开始,反复调用该迭代器的 `next()` 方法。如果其返回值不是 `nil`,它将会被赋给 `item`,然后执行循环体语句,执行完毕后回到循环开始处,继续重复这一过程;否则,既不会赋值也不会执行循环体语句,`for-in` 语句至此执行完毕。
|
||||
|
||||
> for-in 语句语法
|
||||
>
|
||||
>
|
||||
<a name="for-in-statement"></a>
|
||||
> *for-in 语句* → **for** **case**<sub>可选</sub> [*模式*](07_Patterns.md#pattern) **in** [*表达式*](04_Expressions.md#expression) [*where 子句*](#where-clause)<sub>可选</sub> [*代码块*](05_Declarations.md#code-block)
|
||||
|
||||
<a name="while_statements"></a>
|
||||
### While 语句
|
||||
###### for-in-statement {#for-in-statement}
|
||||
> *for-in 语句* → **for** **case**<sub>可选</sub> [*模式*](./08_Patterns.md#pattern) **in** [*表达式*](./04_Expressions.md#expression) [*where 子句*](#where-clause)<sub>可选</sub> [*代码块*](05_Declarations.md#code-block)
|
||||
>
|
||||
|
||||
### While 语句 {#while_statements}
|
||||
只要循环条件为真,`while` 语句就会重复执行代码块。
|
||||
|
||||
`while` 语句的形式如下:
|
||||
@ -78,23 +87,27 @@ while condition {
|
||||
条件的结果必须是 Bool 类型或者 Bool 的桥接类型。另外,条件语句也可以使用可选绑定,请参阅 [可选绑定](../chapter2/01_The_Basics.md#optional_binding)。
|
||||
|
||||
> while 语句语法
|
||||
>
|
||||
>
|
||||
<a name="while-statement"></a>
|
||||
###### while-statement {#while-statement}
|
||||
> *while 语句* → **while** [*条件子句*](#condition-clause) [*代码块*](05_Declarations.md#code-block)
|
||||
>
|
||||
|
||||
<a name="condition-clause"></a>
|
||||
> *条件子句* → [*表达式*](04_Expressions.md#expression) | [*表达式*](04_Expressions.md#expression) **,** [*条件列表*](#condition-list)
|
||||
<a name="condition"></a>
|
||||
> *条件* → [*表达式*](04_Expressions.md#expression) |[*可用性条件*](#availability-condition) | [*case 条件*](#case-condition) | [*可选绑定条件*](#optional-binding-condition)
|
||||
###### condition-clause {#condition-clause}
|
||||
> *条件子句* → [*表达式*](./04_Expressions.md#expression) | [*表达式*](./04_Expressions.md#expression) **,** [*条件列表*](#condition-list)
|
||||
>
|
||||
###### condition {#condition}
|
||||
> *条件* → [*表达式*](./04_Expressions.md#expression) |[*可用性条件*](#availability-condition) | [*case 条件*](#case-condition) | [*可选绑定条件*](#optional-binding-condition)
|
||||
>
|
||||
>
|
||||
<a name="case-condition"></a>
|
||||
> *case 条件* → **case** [*模式*](07_Patterns.md#pattern) [*构造器*](05_Declarations.md#initializer)
|
||||
<a name="optional-binding-condition"></a>
|
||||
> *可选绑定条件* → **let** [*模式*](07_Patterns.md#pattern) [*构造器*](05_Declarations.md#initializer) | **var** [*模式*](07_Patterns.md#pattern) [*构造器*](05_Declarations.md#initializer)
|
||||
|
||||
<a name="repeat-while_statements"></a>
|
||||
### Repeat-While 语句
|
||||
###### case-condition {#case-condition}
|
||||
> *case 条件* → **case** [*模式*](./08_Patterns.md#pattern) [*构造器*](./06_Declarations.md#initializer)
|
||||
>
|
||||
###### optional-binding-condition {#optional-binding-condition}
|
||||
> *可选绑定条件* → **let** [*模式*](./08_Patterns.md#pattern) [*构造器*](./06_Declarations.md#initializer) | **var** [*模式*](./08_Patterns.md#pattern) [*构造器*](./06_Declarations.md#initializer)
|
||||
>
|
||||
|
||||
### Repeat-While 语句 {#repeat-while_statements}
|
||||
`repeat-while` 语句至少执行一次代码块,之后只要循环条件为真,就会重复执行代码块。
|
||||
|
||||
`repeat-while` 语句的形式如下:
|
||||
@ -115,27 +128,29 @@ repeat {
|
||||
条件的结果必须是 Bool 类型或者 Bool 的桥接类型。另外,条件语句也可以使用可选绑定,请参阅 [可选绑定](../chapter2/01_The_Basics.md#optional_binding)。
|
||||
|
||||
> repeat-while 语句语法
|
||||
>
|
||||
>
|
||||
<a name="repeat-while-statement"></a>
|
||||
> *repeat-while 语句* → **repeat** [*代码块*](05_Declarations.md#code-block) **while** [*表达式*](04_Expressions.md#expression)
|
||||
|
||||
<a name="branch_statements"></a>
|
||||
## 分支语句
|
||||
###### repeat-while-statement {#repeat-while-statement}
|
||||
> *repeat-while 语句* → **repeat** [*代码块*](./06_Declarations.md#code-block) **while** [*表达式*](./04_Expressions.md#expression)
|
||||
>
|
||||
|
||||
## 分支语句 {#branch_statements}
|
||||
分支语句会根据一个或者多个条件来执行指定部分的代码。分支语句中的条件将会决定程序如何分支以及执行哪部分代码。Swift 提供三种类型的分支语句:`if` 语句、 `guard` 语句和 `switch` 语句。
|
||||
|
||||
`if` 语句和 `switch` 语句中的控制流可以用 `break` 语句改变,请参阅 [Break 语句](#break_statement)。
|
||||
|
||||
> 分支语句语法
|
||||
>
|
||||
>
|
||||
<a name="branch-statement"></a>
|
||||
###### branch-statement {#branch-statement}
|
||||
> *分支语句* → [*if 语句*](#if-statement)
|
||||
>
|
||||
> *分支语句* → [*guard 语句*](#guard-statement)
|
||||
>
|
||||
> *分支语句* → [*switch 语句*](#switch-statement)
|
||||
>
|
||||
|
||||
<a name="if_statements"></a>
|
||||
### If 语句
|
||||
|
||||
### If 语句 {#if_statements}
|
||||
`if` 语句会根据一个或多个条件来决定执行哪一块代码。
|
||||
|
||||
`if` 语句有两种基本形式,无论哪种形式,都必须有花括号。
|
||||
@ -173,15 +188,16 @@ if condition 1 {
|
||||
`if` 语句中条件的结果必须是 Bool 类型或者 Bool 的桥接类型。另外,条件语句也可以使用可选绑定,请参阅 [可选绑定](../chapter2/01_The_Basics.md#optional_binding)。
|
||||
|
||||
> if 语句语法
|
||||
>
|
||||
>
|
||||
<a name="if-statement"></a>
|
||||
###### if-statement {#if-statement}
|
||||
> *if 语句* → **if** [*条件子句*](#condition-clause) [*代码块*](05_Declarations.md#code-block) [*else 子句*](#else-clause)<sub>可选</sub>
|
||||
<a name="else-clause"></a>
|
||||
> *else 子句* → **else** [*代码块*](05_Declarations.md#code-block) | **else** [*if 语句*](#if-statement)
|
||||
|
||||
<a name="guard_statements"></a>
|
||||
### Guard 语句
|
||||
>
|
||||
###### else-clause {#else-clause}
|
||||
> *else 子句* → **else** [*代码块*](./06_Declarations.md#code-block) | **else** [*if 语句*](#if-statement)
|
||||
>
|
||||
|
||||
### Guard 语句 {#guard_statements}
|
||||
如果一个或者多个条件不成立,可用 `guard` 语句来退出当前作用域。
|
||||
|
||||
`guard` 语句的格式如下:
|
||||
@ -192,7 +208,7 @@ guard condition else {
|
||||
}
|
||||
```
|
||||
|
||||
`guard` 语句中条件的结果必须是 Bool 类型或者 Bool 的桥接类型。另外,条件也可以是一条可选绑定,请参阅 [可选绑定](../chapter2/01_The_Basics.html#optional_binding)。
|
||||
`guard` 语句中条件的结果必须是 Bool 类型或者 Bool 的桥接类型。另外,条件也可以是一条可选绑定,请参阅 [可选绑定](../chapter2/01_The_Basics.md#optional_binding)。
|
||||
|
||||
在 `guard` 语句中进行可选绑定的任何常量或者变量,其可用范围从声明开始直到作用域结束。
|
||||
|
||||
@ -206,13 +222,13 @@ guard condition else {
|
||||
关于控制转移语句,请参阅 [控制转移语句](#control_transfer_statements)。关于 `Never` 返回类型的函数,请参阅 [永不返回的函数](05_Declarations.md#rethrowing_functions_and_methods)。
|
||||
|
||||
> guard 语句语法
|
||||
>
|
||||
>
|
||||
<a name="guard-statement"></a>
|
||||
> *guard 语句* → **guard** [*条件子句*](#condition-clause) **else** [*代码块*] (05_Declarations.html#code-block)
|
||||
|
||||
<a name="switch_statements"></a>
|
||||
### Switch 语句
|
||||
###### guard-statement {#guard-statement}
|
||||
> *guard 语句* → **guard** [*条件子句*](#condition-clause) **else** [*代码块*] (05_Declarations.md#code-block)
|
||||
>
|
||||
|
||||
### Switch 语句 {#switch_statements}
|
||||
`switch` 语句会根据控制表达式的值来决定执行哪部分代码。
|
||||
|
||||
`switch` 语句的形式如下:
|
||||
@ -233,7 +249,7 @@ default:
|
||||
|
||||
`switch` 语句会先计算*控制表达式*的值,然后与每一个 `case` 的模式进行匹配。如果匹配成功,程序将会执行对应的 `case` 中的语句。另外,每一个 `case` 的作用域都不能为空,也就是说在每一个 `case` 的冒号(`:`)后面必须至少有一条语句。如果你不想在匹配到的 `case` 中执行代码,只需在该 `case` 中写一条 `break` 语句即可。
|
||||
|
||||
可以用作控制表达式的值是十分灵活的。除了标量类型外,如 `Int`、`Character`,你可以使用任何类型的值,包括浮点数、字符串、元组、自定义类型的实例和可选类型。控制表达式的值还可以用来匹配枚举类型中的成员值或是检查该值是否包含在指定的 `Range` 中。关于如何在 `switch` 语句中使用这些类型,请参阅 [控制流](../chapter2/05_Control_Flow.html) 一章中的 [Switch](../chapter2/05_Control_Flow.html#switch)。
|
||||
可以用作控制表达式的值是十分灵活的。除了标量类型外,如 `Int`、`Character`,你可以使用任何类型的值,包括浮点数、字符串、元组、自定义类型的实例和可选类型。控制表达式的值还可以用来匹配枚举类型中的成员值或是检查该值是否包含在指定的 `Range` 中。关于如何在 `switch` 语句中使用这些类型,请参阅 [控制流](../chapter2/05_Control_Flow.md) 一章中的 [Switch](../chapter2/05_Control_Flow.md#switch)。
|
||||
|
||||
每个 `case` 的模式后面可以有一个 `where` 子句。`where` 子句由 `where` 关键字紧跟一个提供额外条件的表达式组成。因此,当且仅当控制表达式匹配一个 `case` 的模式且 `where` 子句的表达式为真时,`case` 中的语句才会被执行。在下面的例子中,控制表达式只会匹配包含两个相等元素的元组,例如 `(1, 1)`:
|
||||
|
||||
@ -251,8 +267,7 @@ case let (x, y) where x == y:
|
||||
|
||||
在 Swift 中,`switch` 语句中控制表达式的每一个可能的值都必须至少有一个 `case` 与之对应。在某些无法面面俱到的情况下(例如,表达式的类型是 `Int`),你可以使用 `default` 分支满足该要求。
|
||||
|
||||
#### 对未来枚举的 `case` 进行 `switch`
|
||||
|
||||
#### 对未来枚举的 `case` 进行 `switch` {#future-case}
|
||||
非冻结枚举(`nonfronzen enumeration`)是一种特殊的枚举类型,它可能在未来会增加新的枚举 `case`,即使这时候你已经编译并且发布了你的应用,所以在 switch 非冻结枚举前需要深思熟虑。当一个库的作者们把一个枚举标记为非冻结的,这意味着他们保留了增加新的枚举 `case` 的权利,并且任何和这个枚举交互的代码都要在不需要重新编译的条件下能够处理那些未来可能新加入的 `case` 。只有那些标准库,比如用 Swift 实现的苹果的一些框架,C 以及 Objective-C 代码才能够声明非冻结枚举。你在 Swift 中声明的枚举不能是非冻结的。
|
||||
|
||||
当你对未来枚举进行 switch 时,你总是需要有一个 `default case`,即使每种枚举类型都已经有对应的 `case` 了。你可以在 default 前标注 `@unknown` ,意思是这个 `case` 应该只匹配未来加入的枚举 `case` 。如果你的 `default case` 中匹配了任何在编译时就能确定的枚举 `case` ,Swift 会抛出一个警告。这可以很好地提醒你库的作者已经新增了一种 `case` ,并且你还没有去处理。
|
||||
@ -279,79 +294,102 @@ case .suppressed:
|
||||
当匹配到的 `case` 中的代码执行完毕后,`switch` 语句会直接退出,而不会继续执行下一个 `case` 。这就意味着,如果你想执行下一个 `case`,需要显式地在当前 `case` 中使用 `fallthrough` 语句。关于 `fallthrough` 语句的更多信息,请参阅 [Fallthrough 语句](#fallthrough_statements)。
|
||||
|
||||
> switch 语句语法
|
||||
>
|
||||
>
|
||||
<a name="switch-statement"></a>
|
||||
> *switch 语句* → **switch** [*表达式*](04_Expressions.html#expression) **{** [*switch-case 列表*](#switch-cases)<sub>可选</sub> **}**
|
||||
<a name="switch-cases"></a>
|
||||
###### switch-statement {#switch-statement}
|
||||
> *switch 语句* → **switch** [*表达式*](./04_Expressions.md#expression) **{** [*switch-case 列表*](#switch-cases)<sub>可选</sub> **}**
|
||||
>
|
||||
###### switch-cases {#switch-cases}
|
||||
> *switch case 列表* → [*switch-case*](#switch-case) [*switch-case 列表*](#switch-cases)<sub>可选</sub>
|
||||
<a name="switch-case"></a>
|
||||
>
|
||||
###### switch-case {#switch-case}
|
||||
> *switch case* → [*case 标签*](#case-label) [*多条语句*](#statements) | [*default 标签*](#default-label) [*多条语句*](#statements) | [*conditional-switch-case*](#conditional-switch-case-label)
|
||||
>
|
||||
|
||||
<a name="case-label"></a>
|
||||
###### case-label {#case-label}
|
||||
> *case 标签* → [*属性*](#switch-case-attributes-label)<sub>可选</sub> **case** [*case 项列表*](#case-item-list) **:**
|
||||
<a name="case-item-list"></a>
|
||||
> *case 项列表* → [*模式*](07_Patterns.md#pattern) [*where 子句*](#where-clause)<sub>可选</sub> | [*模式*](07_Patterns.md#pattern) [*where 子句*](#where-clause)<sub>可选</sub> **,** [*case 项列表*](#case-item-list)
|
||||
<a name="default-label"></a>
|
||||
>
|
||||
###### case-item-list {#case-item-list}
|
||||
> *case 项列表* → [*模式*](./08_Patterns.md#pattern) [*where 子句*](#where-clause)<sub>可选</sub> | [*模式*](07_Patterns.md#pattern) [*where 子句*](#where-clause)<sub>可选</sub> **,** [*case 项列表*](#case-item-list)
|
||||
>
|
||||
###### default-label {#default-label}
|
||||
> *default 标签* → [*属性*](#switch-case-attributes-label)<sub>可选</sub> **default** **:**
|
||||
>
|
||||
>
|
||||
<a name="where-clause"></a>
|
||||
###### where-clause {#where-clause}
|
||||
> *where-clause* → **where** [*where 表达式*](#where-expression)
|
||||
<a name="where-expression"></a>
|
||||
> *where-expression* → [*表达式*](04_Expressions.md#expression)
|
||||
>
|
||||
###### where-expression {#where-expression}
|
||||
> *where-expression* → [*表达式*](./04_Expressions.md#expression)
|
||||
>
|
||||
>
|
||||
<a name="grammar_conditional-switch-case"></a>
|
||||
###### grammar_conditional-switch-case {#grammar_conditional-switch-case}
|
||||
> *conditional-switch-case* → [*switch-if-directive-clause*](#switch-case-attributes-label) [*switch-elseif-directive-clauses*](#switch-case-attributes-label) <sub>可选</sub> [*switch-else-directive-clause*](#switch-case-attributes-label) <sub>可选</sub> [*endif-directive*](#switch-case-attributes-label)
|
||||
<a name="grammar_switch-if-directive-clause"></a>
|
||||
>
|
||||
###### grammar_switch-if-directive-clause {#grammar_switch-if-directive-clause}
|
||||
> *switch-if-directive 语句* → [*if-directive*](#switch-case-attributes-label) [*compilation-condition*](#switch-case-attributes-label) [*switch-cases*](#switch-case-attributes-label) <sub>可选</sub>
|
||||
<a name="grammar_switch-elseif-directive-clauses"></a>
|
||||
>
|
||||
###### grammar_switch-elseif-directive-clauses {#grammar_switch-elseif-directive-clauses}
|
||||
> *switch-elseif-directive 语句(复数)* → [*elseif-directive-clause*](#switch-case-attributes-label) [*switch-elseif-directive-clauses*](#switch-case-attributes-label)<sub>可选</sub>
|
||||
<a name="grammar_switch-elseif-directive-clause"></a>
|
||||
>
|
||||
###### grammar_switch-elseif-directive-clause {#grammar_switch-elseif-directive-clause}
|
||||
> *switch-elseif-directive 语句* → [*elseif-directive*](#switch-case-attributes-label) [*compilation-condition*](#switch-case-attributes-label) [*switch-cases*](#switch-case-attributes-label)<sub>可选</sub>
|
||||
<a name="grammar_switch-else-directive-clause"></a>
|
||||
>
|
||||
###### grammar_switch-else-directive-clause {#grammar_switch-else-directive-clause}
|
||||
> *switch-else-directive 语句* → [*else-directive*](#switch-case-attributes-label) [*switch-cases*](#switch-case-attributes-label) <sub>可选</sub>
|
||||
>
|
||||
|
||||
<a name="labeled_statements"></a>
|
||||
## 带标签的语句
|
||||
|
||||
## 带标签的语句 {#labeled_statements}
|
||||
你可以在循环语句或 `switch` 语句前面加上标签,它由标签名和紧随其后的冒号(`:`)组成。在 `break` 和 `continue` 后面跟上标签名可以显式地在循环语句或 `switch` 语句中改变相应的控制流。关于这两条语句用法,请参阅 [Break 语句](#break_statement) 和 [Continue 语句](#continue_statement)。
|
||||
|
||||
标签的作用域在该标签所标记的语句内。可以嵌套使用带标签的语句,但标签名必须唯一。
|
||||
|
||||
关于使用带标签的语句的例子,请参阅 [控制流](../chapter2/05_Control_Flow.html) 一章中的 [带标签的语句](../chapter2/05_Control_Flow.html#labeled_statements)。
|
||||
关于使用带标签的语句的例子,请参阅 [控制流](../chapter2/05_Control_Flow.md) 一章中的 [带标签的语句](../chapter2/05_Control_Flow.md#labeled_statements)。
|
||||
|
||||
> 带标签的语句语法
|
||||
>
|
||||
>
|
||||
<a name="labeled-statement"></a>
|
||||
###### labeled-statement {#labeled-statement}
|
||||
> *带标签的语句* → [*语句标签*](#statement-label) [*循环语句*](#grammar_loop-statement)
|
||||
>
|
||||
> *带标签的语句* → [*语句标签*](#statement-label) [*if 语句*](#if-statement)
|
||||
>
|
||||
> *带标签的语句* → [*语句标签*](#statement-label) [*switch 语句*](#switch-statement)
|
||||
>
|
||||
> > *带标签的语句* → [*语句标签*](#statement-label) [*do 语句*](#sdo-statement)
|
||||
<a name="statement-label"></a>
|
||||
>
|
||||
###### statement-label {#statement-label}
|
||||
> *语句标签* → [*标签名称*](#label-name) **:**
|
||||
<a name="label-name"></a>
|
||||
> *标签名称* → [*标识符*](02_Lexical_Structure.md#identifier)
|
||||
|
||||
<a name="control_transfer_statements"></a>
|
||||
## 控制转移语句
|
||||
>
|
||||
###### label-name {#label-name}
|
||||
> *标签名称* → [*标识符*](./02_Lexical_Structure.md#identifier)
|
||||
>
|
||||
|
||||
## 控制转移语句 {#control_transfer_statements}
|
||||
控制转移语句能够无条件地把控制权从一片代码转移到另一片代码,从而改变代码执行的顺序。Swift 提供五种类型的控制转移语句:`break` 语句、`continue` 语句、`fallthrough` 语句、`return` 语句和 `throw` 语句。
|
||||
|
||||
> 控制转移语句语法
|
||||
>
|
||||
>
|
||||
<a name="control-transfer-statement"></a>
|
||||
###### control-transfer-statement {#control-transfer-statement}
|
||||
> *控制转移语句* → [*break 语句*](#break-statement)
|
||||
>
|
||||
> *控制转移语句* → [*continue 语句*](#continue-statement)
|
||||
>
|
||||
> *控制转移语句* → [*fallthrough 语句*](#fallthrough-statement)
|
||||
>
|
||||
> *控制转移语句* → [*return 语句*](#return-statement)
|
||||
>
|
||||
> *控制转移语句* → [*throw 语句*](#throw-statement)
|
||||
>
|
||||
|
||||
<a name="break_statement"></a>
|
||||
### Break 语句
|
||||
|
||||
### Break 语句 {#break_statement}
|
||||
`break` 语句用于终止循环语句、`if` 语句或 `switch` 语句的执行。使用 `break` 语句时,可以只写 `break` 这个关键词,也可以在 `break` 后面跟上标签名,像下面这样:
|
||||
|
||||
> break
|
||||
>
|
||||
> break `label name`
|
||||
>
|
||||
|
||||
当 `break` 语句后面带标签名时,可用于终止由这个标签标记的循环语句、`if` 语句或 `switch` 语句的执行。
|
||||
|
||||
@ -359,20 +397,22 @@ case .suppressed:
|
||||
|
||||
无论哪种情况,控制权都会被转移给被终止的控制流语句后面的第一行语句。
|
||||
|
||||
关于使用 `break` 语句的例子,请参阅 [控制流](../chapter2/05_Control_Flow.html) 一章的 [Break](../chapter2/05_Control_Flow.html#break) 和 [带标签的语句](../chapter2/05_Control_Flow.html#labeled_statements)。
|
||||
关于使用 `break` 语句的例子,请参阅 [控制流](../chapter2/05_Control_Flow.md) 一章的 [Break](../chapter2/05_Control_Flow.md#break) 和 [带标签的语句](../chapter2/05_Control_Flow.md#labeled_statements)。
|
||||
|
||||
> break 语句语法
|
||||
>
|
||||
>
|
||||
<a name="break-statement"></a>
|
||||
###### break-statement {#break-statement}
|
||||
> *break 语句* → **break** [*标签名称*](#label-name)<sub>可选</sub>
|
||||
>
|
||||
|
||||
<a name="continue_statement"></a>
|
||||
### Continue 语句
|
||||
|
||||
### Continue 语句 {#continue_statement}
|
||||
`continue` 语句用于终止循环中当前迭代的执行,但不会终止该循环的执行。使用 `continue` 语句时,可以只写 `continue` 这个关键词,也可以在 `continue` 后面跟上标签名,像下面这样:
|
||||
|
||||
> continue
|
||||
>
|
||||
> continue `label name`
|
||||
>
|
||||
|
||||
当 `continue` 语句后面带标签名时,可用于终止由这个标签标记的循环中当前迭代的执行。
|
||||
|
||||
@ -382,53 +422,57 @@ case .suppressed:
|
||||
|
||||
在 `for` 语句中,`continue` 语句执行后,增量表达式还是会被计算,这是因为每次循环体执行完毕后,增量表达式都会被计算。
|
||||
|
||||
关于使用 `continue` 语句的例子,请参阅 [控制流](../chapter2/05_Control_Flow.html) 一章的 [Continue](../chapter2/05_Control_Flow.html#continue) 和 [带标签的语句](../chapter2/05_Control_Flow.html#labeled_statements)。
|
||||
关于使用 `continue` 语句的例子,请参阅 [控制流](../chapter2/05_Control_Flow.md) 一章的 [Continue](../chapter2/05_Control_Flow.md#continue) 和 [带标签的语句](../chapter2/05_Control_Flow.md#labeled_statements)。
|
||||
|
||||
> continue 语句语法
|
||||
>
|
||||
>
|
||||
<a name="continue-statement"></a>
|
||||
###### continue-statement {#continue-statement}
|
||||
> *continue 语句* → **continue** [*标签名称*](#label-name)<sub>可选</sub>
|
||||
>
|
||||
|
||||
<a name="fallthrough_statements"></a>
|
||||
### Fallthrough 语句
|
||||
|
||||
### Fallthrough 语句 {#fallthrough_statements}
|
||||
`fallthrough` 语句用于在 `switch` 语句中转移控制权。`fallthrough` 语句会把控制权从 `switch` 语句中的一个 `case` 转移到下一个 `case`。这种控制权转移是无条件的,即使下一个 `case` 的模式与 `switch` 语句的控制表达式的值不匹配。
|
||||
|
||||
`fallthrough` 语句可出现在 `switch` 语句中的任意 `case` 中,但不能出现在最后一个 `case` 中。同时,`fallthrough` 语句也不能把控制权转移到使用了值绑定的 `case`。
|
||||
|
||||
关于在 `switch` 语句中使用 `fallthrough` 语句的例子,请参阅 [控制流](../chapter2/05_Control_Flow.html) 一章的 [控制转移语句](../chapter2/05_Control_Flow.html#control_transfer_statements)。
|
||||
关于在 `switch` 语句中使用 `fallthrough` 语句的例子,请参阅 [控制流](../chapter2/05_Control_Flow.md) 一章的 [控制转移语句](../chapter2/05_Control_Flow.md#control_transfer_statements)。
|
||||
|
||||
> fallthrough 语句语法
|
||||
>
|
||||
>
|
||||
<a name="fallthrough-statement"></a>
|
||||
###### fallthrough-statement {#fallthrough-statement}
|
||||
> *fallthrough 语句* → **fallthrough**
|
||||
>
|
||||
|
||||
<a name="return_statements"></a>
|
||||
### Return 语句
|
||||
|
||||
### Return 语句 {#return_statements}
|
||||
`return` 语句用于在函数或方法的实现中将控制权转移到调用函数或方法,接着程序将会从调用位置继续向下执行。
|
||||
|
||||
使用 `return` 语句时,可以只写 `return` 这个关键词,也可以在 `return` 后面跟上表达式,像下面这样:
|
||||
|
||||
> return
|
||||
>
|
||||
> return `expression`
|
||||
>
|
||||
|
||||
当 `return` 语句后面带表达式时,表达式的值将会返回给调用函数或方法。如果表达式的值的类型与函数或者方法声明的返回类型不匹配,Swift 则会在返回表达式的值之前将表达式的值的类型转换为返回类型。
|
||||
|
||||
> 注意
|
||||
>
|
||||
>
|
||||
> 正如 [可失败构造器](05_Declarations.html#failable_initializers) 中所描述的,`return nil` 在可失败构造器中用于表明构造失败。
|
||||
> 正如 [可失败构造器](./06_Declarations.md#failable_initializers) 中所描述的,`return nil` 在可失败构造器中用于表明构造失败。
|
||||
>
|
||||
|
||||
而只写 `return` 时,仅仅是从该函数或方法中返回,而不返回任何值(也就是说,函数或方法的返回类型为 `Void` 或者说 `()`)。
|
||||
|
||||
> return 语句语法
|
||||
>
|
||||
>
|
||||
<a name="return-statement"></a>
|
||||
> *return 语句* → **return** [*表达式*](04_Expressions.html#expression)<sub>可选</sub>
|
||||
|
||||
<a name="throw_statements"></a>
|
||||
### Throw 语句
|
||||
###### return-statement {#return-statement}
|
||||
> *return 语句* → **return** [*表达式*](./04_Expressions.md#expression)<sub>可选</sub>
|
||||
>
|
||||
|
||||
### Throw 语句 {#throw_statements}
|
||||
`throw` 语句出现在抛出函数或者抛出方法体内,或者类型被 `throws` 关键字标记的闭包表达式体内。
|
||||
|
||||
`throw` 语句使程序在当前作用域结束执行,并向外围作用域传播错误。抛出的错误会一直传递,直到被 `do` 语句的 `catch` 子句处理掉。
|
||||
@ -436,19 +480,20 @@ case .suppressed:
|
||||
`throw` 语句由 `throw` 关键字紧跟一个表达式组成,如下所示:
|
||||
|
||||
> throw `expression`
|
||||
>
|
||||
|
||||
表达式的结果必须符合 `ErrorType` 协议。
|
||||
|
||||
关于如何使用 `throw` 语句的例子,请参阅 [错误处理](../chapter2/18_Error_Handling.html) 一章的 [用 throwing 函数传递错误](../chapter2/18_Error_Handling.html#propagating_errors_using_throwing_functions)。
|
||||
关于如何使用 `throw` 语句的例子,请参阅 [错误处理](../chapter2/17_Error_Handling.md) 一章的 [用 throwing 函数传递错误](../chapter2/17_Error_Handling.md#propagating_errors_using_throwing_functions)。
|
||||
|
||||
> throw 语句语法
|
||||
>
|
||||
>
|
||||
<a name="throw-statement"></a>
|
||||
> *throw 语句* → **throw** [*表达式*](04_Expressions.html#expression)
|
||||
|
||||
<a name="defer_statements"></a>
|
||||
## Defer 语句
|
||||
###### throw-statement {#throw-statement}
|
||||
> *throw 语句* → **throw** [*表达式*](./04_Expressions.md#expression)
|
||||
>
|
||||
|
||||
## Defer 语句 {#defer_statements}
|
||||
`defer` 语句用于在退出当前作用域之前执行代码。
|
||||
|
||||
`defer` 语句形式如下:
|
||||
@ -478,13 +523,13 @@ f()
|
||||
`defer` 语句中的语句无法将控制权转移到 `defer` 语句外部。
|
||||
|
||||
> defer 语句语法
|
||||
>
|
||||
>
|
||||
<a name="defer-statement"></a>
|
||||
> *延迟语句* → **defer** [*代码块*](05_Declarations.html#code-block)
|
||||
|
||||
<a name="do_statements"></a>
|
||||
## Do 语句
|
||||
###### defer-statement {#defer-statement}
|
||||
> *延迟语句* → **defer** [*代码块*](./06_Declarations.md#code-block)
|
||||
>
|
||||
|
||||
## Do 语句 {#do_statements}
|
||||
`do` 语句用于引入一个新的作用域,该作用域中可以含有一个或多个 `catch` 子句,`catch` 子句中定义了一些匹配错误条件的模式。`do` 语句作用域内定义的常量和变量只能在 `do` 语句作用域内使用。
|
||||
|
||||
Swift 中的 `do` 语句与 C 中限定代码块界限的大括号(`{}`)很相似,也并不会降低程序运行时的性能。
|
||||
@ -504,34 +549,38 @@ do {
|
||||
|
||||
如同 `switch` 语句,编译器会判断 `catch` 子句是否有遗漏。如果 `catch` 子句没有遗漏,则认为错误已被处理。否则,错误会自动传递到外围作用域,被某个 `catch` 子句处理掉或者被用 `throws` 关键字声明的抛出函数继续向外抛出。
|
||||
|
||||
为了确保错误已经被处理,可以让 `catch` 子句使用匹配所有错误的模式,如通配符模式(`_`)。如果一个 `catch` 子句不指定一种具体模式,`catch` 子句会匹配任何错误,并绑定到名为 `error` 的局部常量。有关在 `catch` 子句中使用模式的更多信息,请参阅 [模式](07_Patterns.html)。
|
||||
为了确保错误已经被处理,可以让 `catch` 子句使用匹配所有错误的模式,如通配符模式(`_`)。如果一个 `catch` 子句不指定一种具体模式,`catch` 子句会匹配任何错误,并绑定到名为 `error` 的局部常量。有关在 `catch` 子句中使用模式的更多信息,请参阅 [模式](./08_Patterns.md)。
|
||||
|
||||
关于如何在 `do` 语句中使用一系列 `catch` 子句的例子,请参阅 [错误处理](../chapter2/17_Error_Handling.html#handling_errors)。
|
||||
关于如何在 `do` 语句中使用一系列 `catch` 子句的例子,请参阅 [错误处理](../chapter2/17_Error_Handling.md#handling_errors)。
|
||||
|
||||
> do 语句语法
|
||||
>
|
||||
>
|
||||
<a name="do-statement"></a>
|
||||
> *do 语句* → **do** [*代码块*](05_Declarations.html#code-block) [*多条 catch 子句*](#catch-clauses)<sub>可选</sub>
|
||||
<a name="catch-clauses"></a>
|
||||
###### do-statement {#do-statement}
|
||||
> *do 语句* → **do** [*代码块*](./06_Declarations.md#code-block) [*多条 catch 子句*](#catch-clauses)<sub>可选</sub>
|
||||
>
|
||||
###### catch-clauses {#catch-clauses}
|
||||
> *多条 catch 子句* → [*catch 子句*](#catch-clause) [*多条 catch 子句*](#catch-clauses)<sub>可选</sub>
|
||||
<a name="catch-clause"></a>
|
||||
> *catch 子句* → **catch** [*模式*](07_Patterns.html#pattern)<sub>可选</sub> [*where 子句*](#where-clause)<sub>可选</sub> [*代码块*](05_Declarations.html#code-block)
|
||||
|
||||
<a name="compiler_control_statements"></a>
|
||||
## 编译器控制语句
|
||||
>
|
||||
###### catch-clause {#catch-clause}
|
||||
> *catch 子句* → **catch** [*模式*](./08_Patterns.md#pattern)<sub>可选</sub> [*where 子句*](#where-clause)<sub>可选</sub> [*代码块*](05_Declarations.md#code-block)
|
||||
>
|
||||
|
||||
## 编译器控制语句 {#compiler_control_statements}
|
||||
编译器控制语句允许程序改变编译器的行为。Swift 有三种编译器控制语句:条件编译语句、线路控制语句和编译时诊断语句。
|
||||
|
||||
> 编译器控制语句语法
|
||||
>
|
||||
>
|
||||
<a name="compiler-control-statement"></a>
|
||||
###### compiler-control-statement {#compiler-control-statement}
|
||||
> *编译器控制语句* → [*条件编译语句*](#grammar_conditional-compilation-block)
|
||||
>
|
||||
> *编译器控制语句* → [*线路控制语句*](#line-control-statement)
|
||||
>
|
||||
> *编译器控制语句* → [*诊断语句*](#grammar_diagnostic-statement)
|
||||
>
|
||||
|
||||
<a name="Conditional_Compilation_Block"></a>
|
||||
### 条件编译代码块
|
||||
|
||||
### 条件编译代码块 {#Conditional_Compilation_Block}
|
||||
条件编译代码块可以根据一个或多个配置来有条件地编译代码。
|
||||
|
||||
每一个条件编译代码块都以 `#if` 开始,`#endif` 结束。如下:
|
||||
@ -577,8 +626,10 @@ print("Compiled with the Swift 5 compiler or later in a Swift mode earlier than
|
||||
`targetEnvironment()` 当为模拟器编译时返回 `true`,否则返回 `false` 。
|
||||
|
||||
> 注意
|
||||
>
|
||||
>
|
||||
> `arch(arm)` 平台检测函数在 ARM 64 位设备上不会返回 `true`。如果代码在 32 位的 iOS 模拟器上编译,`arch(i386)` 平台检测函数会返回 `true`。
|
||||
>
|
||||
|
||||
你可以使用逻辑操作符 `&&`、`||` 和 `!` 来组合多个编译配置,还可以使用圆括号来进行分组。
|
||||
|
||||
@ -595,88 +646,124 @@ statements to compile if both compilation conditions are false
|
||||
```
|
||||
|
||||
> 注意
|
||||
>
|
||||
>
|
||||
> 即使没有被编译,编译配置中的语句仍然会被解析。然而,唯一的例外是编译配置语句中包含语言版本检测函数:仅当 `Swift` 编译器版本和语言版本检测函数中指定的版本号匹配时,语句才会被解析。这种设定能确保旧的编译器不会尝试去解析新 Swift 版本的语法。
|
||||
>
|
||||
|
||||
<a name="build-config-statement"></a>
|
||||
###### build-config-statement {#build-config-statement}
|
||||
> 条件编译代码块语法
|
||||
>
|
||||
>
|
||||
<a name="grammar_conditional-compilation-block"></a>
|
||||
###### grammar_conditional-compilation-block {#grammar_conditional-compilation-block}
|
||||
> *条件编译代码块* → [*if-directive 语句*](#grammar_if-directive-clause) [*elseif-directive 语句(复数)*](#grammar_elseif-directive-clauses)<sub>可选</sub> [*else-directive 语句*](#grammar_else-directive-clause)<sub>可选</sub> [*endif-directive*](#grammar_endif-directive)
|
||||
<a name="grammar_if-directive-clause"></a>
|
||||
>
|
||||
###### grammar_if-directive-clause {#grammar_if-directive-clause}
|
||||
> *if-directive 语句* → [*if-directive*](#grammar_if-directive) [*编译条件*](#compilation-condition) [*语句(复数)*](#statements)<sub>可选</sub>
|
||||
<a name="grammar_elseif-directive-clauses"></a>
|
||||
>
|
||||
###### grammar_elseif-directive-clauses {#grammar_elseif-directive-clauses}
|
||||
> *elseif-directive 语句(复数)* → [*elseif-directive 语句*](#grammar_elseif-directive-clause) [*elseif-directive 语句(复数)*](#grammar_elseif-directive-clauses)
|
||||
<a name="grammar_elseif-directive-clauses"></a>
|
||||
>
|
||||
###### grammar_elseif-directive-clauses {#grammar_elseif-directive-clauses}
|
||||
> *elseif-directive 语句* → [*elseif-directive*](#grammar_elseif-directive) [*编译条件*](#compilation-condition) [*语句(复数)*](#statements)<sub>可选</sub>
|
||||
<a name="grammar_else-directive-clause"></a>
|
||||
>
|
||||
###### grammar_else-directive-clause {#grammar_else-directive-clause}
|
||||
> *else-directive 语句* → [*else-directive*](#grammar_else-directive) [*语句(复数)*](#statements)<sub>可选</sub>
|
||||
>
|
||||
|
||||
|
||||
> *if-directive* → **#if**
|
||||
>
|
||||
> *elseif-directive* → **#elseif**
|
||||
>
|
||||
> *else-directive* → **#else**
|
||||
>
|
||||
> *endif-directive* → **#endif**
|
||||
>
|
||||
|
||||
<a name="compilation-condition"></a>
|
||||
###### compilation-condition {#compilation-condition}
|
||||
> *编译条件* → [*平台条件*](#grammar_platform-condition)
|
||||
> *编译条件* → [*标识符*](02_Lexical_Structure.md#identifier)
|
||||
> *编译条件* → [*布尔值字面量*](02_Lexical_Structure.md#boolean-literal)
|
||||
>
|
||||
> *编译条件* → [*标识符*](./02_Lexical_Structure.md#identifier)
|
||||
>
|
||||
> *编译条件* → [*布尔值字面量*](./02_Lexical_Structure.md#boolean-literal)
|
||||
>
|
||||
> *编译条件* → **(** [*编译条件*](#compilation-condition) **)**
|
||||
>
|
||||
> *编译条件* → **!** [*编译条件*](#compilation-condition)
|
||||
>
|
||||
> *编译条件* → [*编译条件*](#compilation-condition) **&&** [*编译条件*](#compilation-condition)
|
||||
>
|
||||
> *编译条件* → [*编译条件*](#compilation-condition) **||** [*编译条件*](#compilation-condition)
|
||||
>
|
||||
|
||||
<a name="grammar_platform-condition"></a>
|
||||
<a name="grammar_platform-condition-os"></a>
|
||||
###### grammar_platform-condition {#grammar_platform-condition}
|
||||
###### grammar_platform-condition-os {#grammar_platform-condition-os}
|
||||
> *平台条件* → **os ( [*操作系统*](#operating-system) )**
|
||||
<a name="grammar_platform-condition-arch"></a>
|
||||
>
|
||||
###### grammar_platform-condition-arch {#grammar_platform-condition-arch}
|
||||
> *平台条件* → **arch ( [*架构*](#architecture) )**
|
||||
<a name="grammar_platform-condition-swift"></a>
|
||||
>
|
||||
###### grammar_platform-condition-swift {#grammar_platform-condition-swift}
|
||||
> *平台条件* → **swift ( >= [*swift 版本*](#swift-version) )** | **swift ( < [*swift 版本*](#swift-version) )**
|
||||
<a name="grammar_platform-condition-compiler"></a>
|
||||
>
|
||||
###### grammar_platform-condition-compiler {#grammar_platform-condition-compiler}
|
||||
> *平台条件* → **compiler ( >= [*swift 版本*](#swift-version) )** | **compiler ( < [*swift 版本*](#swift-version) )**
|
||||
<a name="grammar_platform-condition-canImport"></a>
|
||||
>
|
||||
###### grammar_platform-condition-canImport {#grammar_platform-condition-canImport}
|
||||
> *平台条件* → **canImport ( [*模块名*](#grammar_module-name) )**
|
||||
<a name="grammar_platform-condition-targetEnvironment"></a>
|
||||
>
|
||||
###### grammar_platform-condition-targetEnvironment {#grammar_platform-condition-targetEnvironment}
|
||||
> *平台条件* → **targetEnvironment ( [*环境*](#grammar_environment) )**
|
||||
<a name="operating-system"></a>
|
||||
>
|
||||
###### operating-system {#operating-system}
|
||||
> *操作系统* → **macOS** | **iOS** | **watchOS** | **tvOS**
|
||||
<a name="architecture"></a>
|
||||
>
|
||||
###### architecture {#architecture}
|
||||
> *架构* → **i386** | **x86_64** | **arm** | **arm64**
|
||||
<a name="swift-version"></a>
|
||||
> *swift 版本* → [*十进制数字*](02_Lexical_Structure.md#decimal-digit) **.** [*swift 版本延续*](#grammar_swift-version-continuation) <sub>可选</sub>
|
||||
<a name="grammar_swift-version-continuation"></a>
|
||||
> *swift 版本延续* → **.** [*十进制数字*](02_Lexical_Structure.md#decimal-digit) [*swift 版本延续*](#grammar_swift-version-continuation) <sub>可选</sub>
|
||||
<a name="grammar_module-name"></a>
|
||||
> *模块名* → [*identifier*](02_Lexical_Structure.md#identifier)
|
||||
<a name="grammar_environment"></a>
|
||||
>
|
||||
###### swift-version {#swift-version}
|
||||
> *swift 版本* → [*十进制数字*](./02_Lexical_Structure.md#decimal-digit) **.** [*swift 版本延续*](#grammar_swift-version-continuation) <sub>可选</sub>
|
||||
>
|
||||
###### grammar_swift-version-continuation {#grammar_swift-version-continuation}
|
||||
> *swift 版本延续* → **.** [*十进制数字*](./02_Lexical_Structure.md#decimal-digit) [*swift 版本延续*](#grammar_swift-version-continuation) <sub>可选</sub>
|
||||
>
|
||||
###### grammar_module-name {#grammar_module-name}
|
||||
> *模块名* → [*identifier*](./02_Lexical_Structure.md#identifier)
|
||||
>
|
||||
###### grammar_environment {#grammar_environment}
|
||||
> *环境* → **模拟器**
|
||||
>
|
||||
|
||||
<a name="line_control_statements"></a>
|
||||
### 行控制语句
|
||||
|
||||
### 行控制语句 {#line_control_statements}
|
||||
行控制语句可以为被编译的源代码指定行号和文件名,从而改变源代码的定位信息,以便进行分析和调试。
|
||||
|
||||
行控制语句形式如下:
|
||||
|
||||
> \#sourceLocation(file: `filename` , line:`line number`)
|
||||
>
|
||||
|
||||
> \#sourceLocation()
|
||||
>
|
||||
|
||||
第一种的行控制语句会改变该语句之后的代码中的字面量表达式 `#line` 和 `#file` 所表示的值。`行号` 是一个大于 0 的整形字面量,会改变 `#line` 表达式的值。`文件名` 是一个字符串字面量,会改变 `#file` 表达式的值。
|
||||
|
||||
第二种的行控制语句,`#sourceLocation()`,会将源代码的定位信息重置回默认的行号和文件名。
|
||||
|
||||
<a name="line-control-statement"></a>
|
||||
###### line-control-statement {#line-control-statement}
|
||||
> 行控制语句语法
|
||||
>
|
||||
>
|
||||
> *行控制语句* → **#sourceLocation(file:[*文件名*](#file-name),line:[*行号*](#line-number))**
|
||||
>
|
||||
> *行控制语句* → **#sourceLocation()**
|
||||
<a name="line-number"></a>
|
||||
>
|
||||
###### line-number {#line-number}
|
||||
> *行号* → 大于 0 的十进制整数
|
||||
<a name="file-name"></a>
|
||||
> *文件名* → [*静态字符串字面量*](02_Lexical_Structure.md#static-string-literal)
|
||||
>
|
||||
###### file-name {#file-name}
|
||||
> *文件名* → [*静态字符串字面量*](./02_Lexical_Structure.md#static-string-literal)
|
||||
>
|
||||
|
||||
### 编译时诊断语句
|
||||
|
||||
@ -690,16 +777,18 @@ statements to compile if both compilation conditions are false
|
||||
第一句会抛出错误信息并终止编译,第二句会发出警告信息但是编译会继续进行。你可以通过静态字符串字面量来书写诊断信息,静态字符串字面量不能使用字符串 `interpolation` 或者 `concatenation`,但可以使用多行的形式。
|
||||
|
||||
> 编译时诊断语句语法
|
||||
>
|
||||
>
|
||||
<a name="grammar_compile-time-diagnostic-statement"></a>
|
||||
###### grammar_compile-time-diagnostic-statement {#grammar_compile-time-diagnostic-statement}
|
||||
> *诊断语句* → **#error** **(** [*diagnostic-message*](#grammar_diagnostic-message) **)**
|
||||
>
|
||||
> *诊断语句* → **#warning** **(** [*diagnostic-message*](#grammar_diagnostic-message) **)**
|
||||
<a name="grammar_diagnostic-message"></a>
|
||||
> *诊断语句* → [*静态字符串字面量*](02_Lexical_Structure.md#static-string-literal)
|
||||
|
||||
<a name="availability_condition"></a>
|
||||
## 可用性条件
|
||||
>
|
||||
###### grammar_diagnostic-message {#grammar_diagnostic-message}
|
||||
> *诊断语句* → [*静态字符串字面量*](./02_Lexical_Structure.md#static-string-literal)
|
||||
>
|
||||
|
||||
## 可用性条件 {#availability_condition}
|
||||
可用性条件可作为 `if`,`while`,`guard` 语句的条件,可以在运行时基于特定的平台参数来查询 API 的可用性。
|
||||
|
||||
可用性条件的形式如下:
|
||||
@ -719,21 +808,33 @@ if #available(platform name version, ..., *) {
|
||||
与布尔类型的条件不同,不能用逻辑运算符 `&&` 和 `||` 组合可用性条件。
|
||||
|
||||
> 可用性条件语法
|
||||
>
|
||||
>
|
||||
<a name="availability-condition"></a>
|
||||
###### availability-condition {#availability-condition}
|
||||
> *可用性条件* → **#available** **(** [*可用性参数列表*](#availability-arguments) **)**
|
||||
<a name="availability-arguments"></a>
|
||||
>
|
||||
###### availability-arguments {#availability-arguments}
|
||||
> *可用性参数列表* → [*可用性参数*](#availability-argument) | [*可用性参数*](#availability-argument) **,** [*可用性参数列表*](#availability-arguments)
|
||||
<a name="availability-argument"></a>
|
||||
>
|
||||
###### availability-argument {#availability-argument}
|
||||
> *可用性参数* → [平台名称](#platform-name) [平台版本](#platform-version)
|
||||
>
|
||||
> *可用性条件* → __*__
|
||||
>
|
||||
>
|
||||
<a name="platform-name"></a>
|
||||
###### platform-name {#platform-name}
|
||||
> *平台名称* → **iOS** | **iOSApplicationExtension**
|
||||
>
|
||||
> *平台名称* → **OSX** | **macOSApplicationExtension**
|
||||
>
|
||||
> *平台名称* → **watchOS**
|
||||
>
|
||||
> *平台名称* → **tvOS**
|
||||
<a name="platform-version"></a>
|
||||
> *平台版本* → [十进制数字](02_Lexical_Structure.md#decimal-digits)
|
||||
> *平台版本* → [十进制数字](02_Lexical_Structure.md#decimal-digits) **.** [十进制数字](02_Lexical_Structure.md#decimal-digits)
|
||||
> *平台版本* → [十进制数字](02_Lexical_Structure.md#decimal-digits) **.** [十进制数字](02_Lexical_Structure.md#decimal-digits) **.** [十进制数字](02_Lexical_Structure.md#decimal-digits)
|
||||
>
|
||||
###### platform-version {#platform-version}
|
||||
> *平台版本* → [十进制数字](./02_Lexical_Structure.md#decimal-digits)
|
||||
>
|
||||
> *平台版本* → [十进制数字](./02_Lexical_Structure.md#decimal-digits) **.** [十进制数字](./02_Lexical_Structure.md#decimal-digits)
|
||||
>
|
||||
> *平台版本* → [十进制数字](./02_Lexical_Structure.md#decimal-digits) **.** [十进制数字](./02_Lexical_Structure.md#decimal-digits) **.** [十进制数字](./02_Lexical_Structure.md#decimal-digits)
|
||||
>
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@ -10,13 +10,11 @@
|
||||
|
||||
有些声明特性通过接收参数来指定特性的更多信息以及它是如何修饰某个特定的声明的。这些_特性的参数_写在圆括号内,它们的格式由它们所属的特性来定义。
|
||||
|
||||
<a name="declaration_attributes"></a>
|
||||
## 声明特性
|
||||
## 声明特性 {#declaration_attributes}
|
||||
|
||||
声明特性只能应用于声明。
|
||||
|
||||
<a name="available"></a>
|
||||
### `available`
|
||||
### `available` {#available}
|
||||
|
||||
将 `available` 特性用于声明时,表示该声明的生命周期是相对于特定的平台和操作系统版本。
|
||||
|
||||
@ -112,13 +110,11 @@ struct MyStruct {
|
||||
}
|
||||
```
|
||||
|
||||
<a name="discardableresult"></a>
|
||||
### `discardableResult`
|
||||
### `discardableResult` {#discardableresult}
|
||||
|
||||
该特性用于的函数或方法声明,以抑制编译器中函数或方法的返回值被调而没有使用其结果的警告。
|
||||
|
||||
<a name="dynamiccallable"></a>
|
||||
### `dynamicCallable`
|
||||
### `dynamicCallable` {#dynamiccallable}
|
||||
|
||||
该特性用于类、结构体、枚举或协议,以将该类型的实例视为可调用的函数。该类型必须实现 `dynamicallyCall(withArguments:)`、`dynamicallyCall(withKeywordArguments:)` 方法之一,或两者同时实现。
|
||||
|
||||
@ -155,6 +151,7 @@ dial.dynamicallyCall(withArguments: [4, 1, 1])
|
||||
@dynamicCallable
|
||||
struct Repeater {
|
||||
func dynamicallyCall(withKeywordArguments pairs: KeyValuePairs<String, Int>) -> String {
|
||||
>
|
||||
return pairs
|
||||
.map { label, count in
|
||||
repeatElement(label, count: count).joined(separator: " ")
|
||||
@ -182,8 +179,7 @@ print(repeatLabels(a: 1, b: 2, c: 3, b: 2, a: 1))
|
||||
repeatLabels(a: "four") // Error
|
||||
```
|
||||
|
||||
<a name="dynamicmemberlookup"></a>
|
||||
### `dynamicMemberLookup`
|
||||
### `dynamicMemberLookup` {#dynamicmemberlookup}
|
||||
|
||||
该特性用于类、结构体、枚举或协议,让其能在运行时查找成员。该类型必须实现 `subscript(dynamicMemberLookup:)` 下标。
|
||||
|
||||
@ -195,6 +191,7 @@ struct DynamicStruct {
|
||||
let dictionary = ["someDynamicMember": 325,
|
||||
"someOtherMember": 787]
|
||||
subscript(dynamicMember member: String) -> Int {
|
||||
>
|
||||
return dictionary[member] ?? 1054
|
||||
}
|
||||
}
|
||||
@ -211,13 +208,11 @@ print(dynamic == equivalent)
|
||||
// 打印“true”
|
||||
```
|
||||
|
||||
<a name="gkinspectable"></a>
|
||||
### `GKInspectable`
|
||||
### `GKInspectable` {#gkinspectable}
|
||||
|
||||
应用此属性,暴露一个自定义 GameplayKit 组件属性给 SpriteKit 编辑器 UI。
|
||||
|
||||
<a name="inlinable"></a>
|
||||
### `inlinable`
|
||||
### `inlinable` {#inlinable}
|
||||
|
||||
该特性用于函数、方法、计算属性、下标、便利构造器或析构器的声明,以将该声明的实现公开为模块公开接口的一部分。编译器允许在调用处把 `inlinable` 标记的符号替换为符号实现的副本。
|
||||
|
||||
@ -225,8 +220,7 @@ print(dynamic == equivalent)
|
||||
|
||||
该特性不能用于嵌套在函数内的声明,也不能用于 `fileprivate` 或 `private` 访问级别的声明。在内联函数定义的函数和闭包是隐式非内联的,即使他们不能标记该特性。
|
||||
|
||||
<a name="nonobjc"></a>
|
||||
### `nonobjc`
|
||||
### `nonobjc` {#nonobjc}
|
||||
|
||||
该特性用于方法、属性、下标、或构造器的声明,这些声明本可以在 Objective-C 代码中使用,而使用 `nonobjc` 特性则告诉编译器这个声明不能在 Objective-C 代码中使用。
|
||||
|
||||
@ -236,8 +230,7 @@ print(dynamic == equivalent)
|
||||
|
||||
标有 `nonobjc` 特性的方法不能重写标有 `objc` 特性的方法。然而,标有 `objc` 特性的方法可以重写标有 `nonobjc` 特性的方法。同样,标有 `nonobjc` 特性的方法不能满足标有 `@objc` 特性的协议中的方法要求。
|
||||
|
||||
<a name="nsapplicationmain"></a>
|
||||
### `NSApplicationMain`
|
||||
### `NSApplicationMain` {#nsapplicationmain}
|
||||
|
||||
在类上使用该特性表示该类是应用程序委托类,使用该特性与调用 `NSApplicationMain(_:_:)` 函数并且把该类的名字作为委托类的名字传递给函数的效果相同。
|
||||
|
||||
@ -248,20 +241,17 @@ import AppKit
|
||||
NSApplicationMain(CommandLine.argc, CommandLine.unsafeArgv)
|
||||
```
|
||||
|
||||
<a name="nscopying"></a>
|
||||
### `NSCopying`
|
||||
### `NSCopying` {#nscopying}
|
||||
|
||||
该特性用于修饰一个类的存储型变量属性。该特性将使属性的设值方法使用传入值的副本进行赋值,这个值由传入值的 `copyWithZone(_:)` 方法返回。该属性的类型必需符合 `NSCopying` 协议。
|
||||
|
||||
`NSCopying` 特性的行为与 Objective-C 中的 `copy` 特性相似。
|
||||
|
||||
<a name="nsmanaged"></a>
|
||||
### `NSManaged`
|
||||
### `NSManaged` {#nsmanaged}
|
||||
|
||||
该特性用于修饰 `NSManagedObject` 子类中的实例方法或存储型变量属性,表明它们的实现由 `Core Data` 在运行时基于相关实体描述动态提供。对于标记了 `NSManaged` 特性的属性,`Core Data` 也会在运行时为其提供存储。应用这个特性也意味着 `objc` 特性。
|
||||
|
||||
<a name="objc"></a>
|
||||
### `objc`
|
||||
### `objc` {#objc}
|
||||
|
||||
该特性用于修饰任何可以在 Objective-C 中表示的声明。比如,非嵌套类、协议、非泛型枚举(仅限原始值为整型的枚举)、类和协议中的属性和方法(包括存取方法)、构造器、析构器以及下标运算符。`objc` 特性告诉编译器这个声明可以在 Objective-C 代码中使用。
|
||||
|
||||
@ -277,7 +267,7 @@ NSApplicationMain(CommandLine.argc, CommandLine.unsafeArgv)
|
||||
|
||||
如果你将 `objc` 特性应用于枚举,每一个枚举用例都会以枚举名称和用例名称组合的方式暴露在 Objective-C 代码中。例如,在 `Planet` 枚举中有一个名为 `Venus` 的用例,该用例暴露在 Objective-C 代码中时叫做 `PlanetVenus`。
|
||||
|
||||
`objc` 特性有一个可选的参数,由标识符构成。当你想把 `objc` 所修饰的实体以一个不同的名字暴露给 Objective-C 时,你就可以使用这个特性参数。你可以使用这个参数来命名类、枚举类型、枚举用例、协议、方法、存取方法以及构造器。如果你要指定类、协议或枚举在 Objective-C 下的名称,在名称上包含三个字母的前缀,如 [Objective-C 编程](https://developer.apple.com/library/content/documentation/Cocoa/Conceptual/ProgrammingWithObjectiveC/Introduction/Introduction.html#//apple_ref/doc/uid/TP40011210) 中的 [约定](https://developer.apple.com/library/content/documentation/Cocoa/Conceptual/ProgrammingWithObjectiveC/Conventions/Conventions.html#//apple_ref/doc/uid/TP40011210-CH10-SW1)。下面的例子把 `ExampleClass` 中的 `enabled` 属性的取值方法暴露给 Objective-C,名字是 `isEnabled`,而不是它原来的属性名。
|
||||
`objc` 特性有一个可选的参数,由标识符构成。当你想把 `objc` 所修饰的实体以一个不同的名字暴露给 Objective-C 时,你就可以使用这个特性参数。你可以使用这个参数来命名类、枚举类型、枚举用例、协议、方法、存取方法以及构造器。如果你要指定类、协议或枚举在 Objective-C 下的名称,在名称上包含三个字母的前缀,如 [Objective-C 编程](https://developer.apple.com/library/archive/documentation/Cocoa/Conceptual/ProgrammingWithObjectiveC/Introduction/Introduction.html#//apple_ref/doc/uid/TP40011210) 中的 [约定](https://developer.apple.com/library/archive/documentation/Cocoa/Conceptual/ProgrammingWithObjectiveC/Conventions/Conventions.html#//apple_ref/doc/uid/TP40011210-CH10-SW1)。下面的例子把 `ExampleClass` 中的 `enabled` 属性的取值方法暴露给 Objective-C,名字是 `isEnabled`,而不是它原来的属性名。
|
||||
|
||||
```swift
|
||||
class ExampleClass: NSObject {
|
||||
@ -289,32 +279,27 @@ class ExampleClass: NSObject {
|
||||
}
|
||||
```
|
||||
|
||||
<a name="objcmembers"></a>
|
||||
### `objcMembers`
|
||||
### `objcMembers` {#objcmembers}
|
||||
|
||||
该特性用于类声明,以将 `objc` 特性应用于该类、扩展、子类以及子类的扩展的所有 Objective-C 兼容成员。
|
||||
|
||||
大多数代码应该使用 `objc` 特性,以暴露所需的声明。如果需要暴露多个声明,可以将其分组到添加 `objc` 特性的扩展中。`objcMembers` 特性为大量使用 Objective-C 运行时的内省工具的库提供了便利。添加不必要的 `objc` 特性会增加二进制体积并影响性能。
|
||||
|
||||
<a name="requires_stored_property_inits"></a>
|
||||
### `requires_stored_property_inits`
|
||||
### `requires_stored_property_inits` {#requires_stored_property_inits}
|
||||
|
||||
该特性用于类声明,以要求类中所有存储属性提供默认值作为其定义的一部分。对于从中继承的任何类都推断出 `NSManagedObject` 特性。
|
||||
|
||||
<a name="testable"></a>
|
||||
### `testable`
|
||||
### `testable` {#testable}
|
||||
|
||||
在导入允许测试的编译模块时,该特性用于修饰 `import` 声明,这样就能访问被导入模块中的任何标有 `internal` 访问级别修饰符的实体,犹如它们被标记了 `public` 访问级别修饰符。测试也可以访问使用 `internal` 或者 `public` 访问级别修饰符标记的类和类成员,就像它们是 `open` 访问修饰符声明的。
|
||||
|
||||
<a name="uiapplicationmain"></a>
|
||||
### `UIApplicationMain`
|
||||
### `UIApplicationMain` {#uiapplicationmain}
|
||||
|
||||
在类上使用该特性表示该类是应用程序委托类,使用该特性与调用 `UIApplicationMain` 函数并且把该类的名字作为委托类的名字传递给函数的效果相同。
|
||||
|
||||
如果你不想使用这个特性,可以提供一个 `main.swift` 文件,并在代码顶层调用 `UIApplicationMain(_:_:_:_:)` 函数。比如,如果你的应用程序使用一个继承于 UIApplication 的自定义子类作为主要类,你可以调用 `UIApplicationMain(_:_:_:_:)` 函数而不是使用该特性。
|
||||
|
||||
<a name="usablefrominline"></a>
|
||||
### `usableFromInline`
|
||||
### `usableFromInline` {#usablefrominline}
|
||||
|
||||
该特性用于函数、方法、计算属性、下标、构造器或析构器的声明,以在同一模块中允许该符号用于内联代码的声明。声明必须具有 `internal` 访问级别修饰符。
|
||||
|
||||
@ -322,16 +307,13 @@ class ExampleClass: NSObject {
|
||||
|
||||
标记为 `inlinable` 特性的声明,在内联代码中可以隐式使用。虽然 `inlinable` 或 `usableFromInline` 可以用于 `internal` 声明,但这两者不能同时使用。
|
||||
|
||||
<a name="warn_unqualified_access"></a>
|
||||
### `warn_unqualified_access`
|
||||
### `warn_unqualified_access` {#warn_unqualified_access}
|
||||
|
||||
该特性应用于顶级函数、实例方法、类方法或静态方法,以在没有前置限定符(例如模块名称、类型名称、实例变量或常量)的情况下使用该函数或方法时触发警告。使用该特性可以帮助减少在同一作用于访问同名函数之间的歧义。
|
||||
|
||||
例如,Swift 标准库包含 [`min(_:_:)`](https://developer.apple.com/documentation/swift/1538339-min/) 顶级函数和用于序列比较元素的 [`min()`](https://developer.apple.com/documentation/swift/sequence/1641174-min) 方法。序列方法声明使用了 `warn_unqualified_access`,以减少在 `Sequence` 扩展中使用它们的歧义。
|
||||
|
||||
<a name="declaration_attributes_used_by_interface_builder"></a>
|
||||
|
||||
### Interface Builder 使用的声明特性
|
||||
### Interface Builder 使用的声明特性 {#declaration_attributes_used_by_interface_builder}
|
||||
|
||||
`Interface Builder` 特性是 `Interface Builder` 用来与 Xcode 同步的声明特性。`Swift` 提供了以下的 `Interface Builder` 特性:`IBAction`,`IBOutlet`,`IBDesignable`,以及 `IBInspectable` 。这些特性与 Objective-C 中对应的特性在概念上是相同的。
|
||||
|
||||
@ -339,18 +321,15 @@ class ExampleClass: NSObject {
|
||||
|
||||
应用 `IBAction`、`IBOutlet`、`IBDesignable` 或者 `IBInspectable` 特性都意味着同时应用 `objc` 特性。
|
||||
|
||||
<a name="type_attributes"></a>
|
||||
## 类型特性
|
||||
## 类型特性 {#type_attributes}
|
||||
|
||||
类型特性只能用于修饰类型。
|
||||
|
||||
<a name="autoclosure"></a>
|
||||
### `autoclosure`
|
||||
### `autoclosure` {#autoclosure}
|
||||
|
||||
这个特性通过把表达式自动封装成无参数的闭包来延迟表达式的计算。它可以修饰类型为返回表达式结果类型的无参数函数类型的函数参数。关于如何使用 autoclosure 特性的例子,请参阅 [自动闭包](https://docs.swift.org/swift-book/LanguageGuide/Closures.html#ID543) 和 [函数类型](https://docs.swift.org/swift-book/ReferenceManual/Types.html#ID449)。
|
||||
这个特性通过把表达式自动封装成无参数的闭包来延迟表达式的计算。它可以修饰类型为返回表达式结果类型的无参数函数类型的函数参数。关于如何使用 autoclosure 特性的例子,请参阅 [自动闭包](../chapter2/07_Closures.md#autoclosures) 和 [函数类型](./03_Types.md#function_type)。
|
||||
|
||||
<a name="convention"></a>
|
||||
### `convention`
|
||||
### `convention` {#convention}
|
||||
|
||||
该特性用于修饰函数类型,它指出了函数调用的约定。
|
||||
|
||||
@ -364,36 +343,51 @@ convention 特性总是与下面的参数之一一起出现。
|
||||
|
||||
使用 C 函数调用约定的函数也可用作使用 Objective-C 块调用约定的函数,同时使用 Objective-C 块调用约定的函数也可用作使用 Swift 函数调用约定的函数。然而,只有非泛型的全局函数、局部函数以及未捕获任何局部变量的闭包,才可以被用作使用 C 函数调用约定的函数。
|
||||
|
||||
<a name="escaping"></a>
|
||||
### `escaping`
|
||||
### `escaping` {#escaping}
|
||||
|
||||
在函数或者方法声明上使用该特性,它表示参数将不会被存储以供延迟执行,这将确保参数不会超出函数调用的生命周期。在使用 `escaping` 声明特性的函数类型中访问属性和方法时不需要显式地使用 `self.`。关于如何使用 `escaping` 特性的例子,请参阅 [逃逸闭包](https://docs.swift.org/swift-book/LanguageGuide/Closures.html#ID546)。
|
||||
在函数或者方法声明上使用该特性,它表示参数将不会被存储以供延迟执行,这将确保参数不会超出函数调用的生命周期。在使用 `escaping` 声明特性的函数类型中访问属性和方法时不需要显式地使用 `self.`。关于如何使用 `escaping` 特性的例子,请参阅 [逃逸闭包](../chapter2/07_Closures.md#escaping_closures)。
|
||||
|
||||
<a name="switch_case_attributes"></a>
|
||||
## Switch Case 特性
|
||||
## Switch Case 特性 {#switch_case_attributes}
|
||||
|
||||
你只能在 switch cases 中使用 switch case 特性。
|
||||
|
||||
### `unknown`
|
||||
|
||||
次特性用于 switch case,表示在编译时该地方不会匹配枚举的任何情况。有关如何使用 `unknown` 特性的示例,可参阅 [Switching over Future Enumeration Cases](https://docs.swift.org/swift-book/ReferenceManual/Statements.html#ID602)。
|
||||
次特性用于 switch case,表示在编译时该地方不会匹配枚举的任何情况。有关如何使用 `unknown` 特性的示例,可参阅 [对未来枚举的 `case` 进行 `switch`](./05_Statements.md#future-case)。
|
||||
|
||||
> 特性语法
|
||||
>
|
||||
>
|
||||
> <a name="attribute"></a>
|
||||
> ###### attribute {#attribute}
|
||||
>
|
||||
> *特性*→ [特性名](#attribute_name) [特性参数子句](#atribute_argument_clause)<sub>可选</sub>
|
||||
> <a name="attribute_name"></a>
|
||||
> *特性名* → [标识符](02_Lexical_Structure.html#identifier)
|
||||
> <a name="atribute_argument_clause"></a>
|
||||
>
|
||||
> ###### attribute_name {#attribute_name}
|
||||
>
|
||||
> *特性名* → [标识符](./02_Lexical_Structure.md#identifier)
|
||||
>
|
||||
> ###### atribute_argument_clause {#atribute_argument_clause}
|
||||
>
|
||||
> *特性参数子句* → **(** [均衡令牌列表](#balanced_tokens)<sub>可选</sub> **)**
|
||||
> <a name="attributes"></a>
|
||||
>
|
||||
> ###### attributes {#attributes}
|
||||
>
|
||||
> *特性列表* → [特性](#attribute) [特性列表](#attributes)<sub>可选</sub>
|
||||
>
|
||||
>
|
||||
> <a name="balanced_tokens"></a>
|
||||
> ###### balanced_tokens {#balanced_tokens}
|
||||
>
|
||||
> *均衡令牌列表* → [均衡令牌](#balanced_token) [均衡令牌列表](#balanced_tokens)<sub>可选</sub>
|
||||
> <a name="balanced_token"></a>
|
||||
>
|
||||
> ###### balanced_token {#balanced_token}
|
||||
>
|
||||
> *均衡令牌* → **(** [均衡令牌列表](#balanced_tokens)<sub>可选</sub> **)**
|
||||
>
|
||||
> *均衡令牌* → **\[** [均衡令牌列表](#balanced_tokens)<sub>可选</sub> **\]**
|
||||
>
|
||||
> *均衡令牌* → **{** [均衡令牌列表](#balanced_tokens)<sub>可选</sub> **}**
|
||||
>
|
||||
> *均衡令牌* → 任意标识符,关键字,字面量或运算符
|
||||
>
|
||||
> *均衡令牌* → 任意标点除了 **(**,**)**,**[**,**]**,**{**,或 **}**
|
||||
>
|
||||
|
||||
@ -10,18 +10,25 @@ Swift 中的模式分为两类:一种能成功匹配任何类型的值,另
|
||||
|
||||
> 模式语法
|
||||
>
|
||||
<a name="pattern"></a>
|
||||
> *模式* → [*通配符模式*](#wildcard_pattern) [*类型标注*](03_Types.html#type-annotation)<sub>可选</sub>
|
||||
> *模式* → [*标识符模式*](#identifier_pattern) [*类型标注*](03_Types.html#type-annotation)<sub>可选</sub>
|
||||
###### pattern {#pattern}
|
||||
> *模式* → [*通配符模式*](#wildcard_pattern) [*类型标注*](03_Types.md#type-annotation)<sub>可选</sub>
|
||||
>
|
||||
> *模式* → [*标识符模式*](#identifier_pattern) [*类型标注*](03_Types.md#type-annotation)<sub>可选</sub>
|
||||
>
|
||||
> *模式* → [*值绑定模式*](#value-binding-pattern)
|
||||
> *模式* → [*元组模式*](#tuple-pattern) [*类型标注*](03_Types.html#type-annotation)<sub>可选</sub>
|
||||
>
|
||||
> *模式* → [*元组模式*](#tuple-pattern) [*类型标注*](03_Types.md#type-annotation)<sub>可选</sub>
|
||||
>
|
||||
> *模式* → [*枚举用例模式*](#enum-case-pattern)
|
||||
>
|
||||
> *模式* → [*可选模式*](#optional-pattern)
|
||||
>
|
||||
> *模式* → [*类型转换模式*](#type-casting-pattern)
|
||||
>
|
||||
> *模式* → [*表达式模式*](#expression-pattern)
|
||||
>
|
||||
|
||||
<a name="wildcard_pattern"></a>
|
||||
## 通配符模式(Wildcard Pattern)
|
||||
## 通配符模式(Wildcard Pattern) {#wildcard_pattern}
|
||||
|
||||
*通配符模式*由一个下划线(`_`)构成,用于匹配并忽略任何值。当你想忽略被匹配的值时可以使用该模式。例如,下面这段代码在闭区间 `1...3` 中迭代,每次迭代都忽略该区间的当前值:
|
||||
|
||||
@ -33,12 +40,11 @@ for _ in 1...3 {
|
||||
|
||||
> 通配符模式语法
|
||||
>
|
||||
<a name="wildcard-pattern"></a>
|
||||
###### wildcard-pattern {#wildcard-pattern}
|
||||
> *通配符模式* → **_**
|
||||
>
|
||||
|
||||
<a name="identifier_pattern"></a>
|
||||
## 标识符模式(Identifier Pattern)
|
||||
|
||||
## 标识符模式(Identifier Pattern) {#identifier_pattern}
|
||||
*标识符模式*匹配任何值,并将匹配的值和一个变量或常量绑定起来。例如,在下面的常量声明中,`someValue` 是一个标识符模式,匹配了 `Int` 类型的 `42`:
|
||||
|
||||
```swift
|
||||
@ -51,12 +57,11 @@ let someValue = 42
|
||||
|
||||
> 标识符模式语法
|
||||
>
|
||||
<a name="identifier-pattern"></a>
|
||||
> *标识符模式* → [*标识符*](02_Lexical_Structure.html#identifier)
|
||||
|
||||
<a name="value-binding_pattern"></a>
|
||||
## 值绑定模式(Value-Binding Pattern)
|
||||
###### identifier-pattern {#identifier-pattern}
|
||||
> *标识符模式* → [*标识符*](./02_Lexical_Structure.md#identifier)
|
||||
>
|
||||
|
||||
## 值绑定模式(Value-Binding Pattern) {#value-binding_pattern}
|
||||
*值绑定模式*把匹配到的值绑定给一个变量或常量。把匹配到的值绑定给常量时,用关键字 `let`,绑定给变量时,用关键字 `var`。
|
||||
|
||||
在值绑定模式中的标识符模式会把新命名的变量或常量与匹配到的值做绑定。例如,你可以拆开一个元组,然后把每个元素绑定到相应的标识符模式中。
|
||||
@ -75,12 +80,11 @@ case let (x, y):
|
||||
|
||||
> 值绑定模式语法
|
||||
>
|
||||
<a name="value-binding-pattern"></a>
|
||||
###### value-binding-pattern {#value-binding-pattern}
|
||||
> *值绑定模式* → **var** [*模式*](#pattern) | **let** [*模式*](#pattern)
|
||||
>
|
||||
|
||||
<a name="tuple_pattern"></a>
|
||||
## 元组模式
|
||||
|
||||
## 元组模式 {#tuple_pattern}
|
||||
*元组模式*是由逗号分隔的,具有零个或多个模式的列表,并由一对圆括号括起来。元组模式匹配相应元组类型的值。
|
||||
|
||||
你可以使用类型标注去限制一个元组模式能匹配哪种元组类型。例如,在常量声明 `let (x, y): (Int, Int) = (1, 2)` 中的元组模式 `(x, y): (Int, Int)` 只匹配两个元素都是 `Int` 类型的元组。
|
||||
@ -105,28 +109,28 @@ let (a): Int = 2 // a: Int = 2
|
||||
|
||||
> 元组模式语法
|
||||
>
|
||||
<a name="tuple-pattern"></a>
|
||||
###### tuple-pattern {#tuple-pattern}
|
||||
> *元组模式* → **(** [*元组模式元素列表*](#tuple-pattern-element-list)<sub>可选</sub> **)**
|
||||
<a name="tuple-pattern-element-list"></a>
|
||||
>
|
||||
###### tuple-pattern-element-list {#tuple-pattern-element-list}
|
||||
> *元组模式元素列表* → [*元组模式元素*](#tuple-pattern-element) | [*元组模式元素*](#tuple-pattern-element) **,** [*元组模式元素列表*](#tuple-pattern-element-list)
|
||||
<a name="tuple-pattern-element"></a>
|
||||
>
|
||||
###### tuple-pattern-element {#tuple-pattern-element}
|
||||
> *元组模式元素* → [*模式*](#pattern)
|
||||
>
|
||||
|
||||
<a name="enumeration_case_pattern"></a>
|
||||
## 枚举用例模式(Enumeration Case Pattern)
|
||||
|
||||
## 枚举用例模式(Enumeration Case Pattern) {#enumeration_case_pattern}
|
||||
*枚举用例模式*匹配现有的某个枚举类型的某个用例。枚举用例模式出现在 `switch` 语句中的 `case` 标签中,以及 `if`、`while`、`guard` 和 `for-in` 语句的 `case` 条件中。
|
||||
|
||||
如果你准备匹配的枚举用例有任何关联的值,则相应的枚举用例模式必须指定一个包含每个关联值元素的元组模式。关于使用 `switch` 语句来匹配包含关联值的枚举用例的例子,请参阅 [关联值](../chapter2/08_Enumerations.html#associated_values)。
|
||||
如果你准备匹配的枚举用例有任何关联的值,则相应的枚举用例模式必须指定一个包含每个关联值元素的元组模式。关于使用 `switch` 语句来匹配包含关联值的枚举用例的例子,请参阅 [关联值](../chapter2/08_Enumerations.md#associated_values)。
|
||||
|
||||
> 枚举用例模式语法
|
||||
>
|
||||
<a name="enum-case-pattern"></a>
|
||||
> *枚举用例模式* → [*类型标识*](03_Types.html#type-identifier)<sub>可选</sub> **.** [*枚举用例名*](05_Declarations.html#enum-case-name) [*元组模式*](#tuple-pattern)<sub>可选</sub>
|
||||
|
||||
<a name="optional_pattern"></a>
|
||||
## 可选模式(Optional Pattern)
|
||||
###### enum-case-pattern {#enum-case-pattern}
|
||||
> *枚举用例模式* → [*类型标识*](./03_Types.md#type-identifier)<sub>可选</sub> **.** [*枚举用例名*](./06_Declarations.md#enum-case-name) [*元组模式*](#tuple-pattern)<sub>可选</sub>
|
||||
>
|
||||
|
||||
## 可选模式(Optional Pattern) {#optional_pattern}
|
||||
*可选模式*匹配包装在一个 `Optional(Wrapped)` 或者 `ExplicitlyUnwrappedOptional(Wrapped)` 枚举中的 `Some(Wrapped)` 用例中的值。可选模式由一个标识符模式和紧随其后的一个问号组成,可以像枚举用例模式一样使用。
|
||||
|
||||
由于可选模式是 `Optional` 和 `ImplicitlyUnwrappedOptional` 枚举用例模式的语法糖,下面两种写法是等效的:
|
||||
@ -159,35 +163,37 @@ for case let number? in arrayOfOptinalInts {
|
||||
|
||||
> 可选模式语法
|
||||
>
|
||||
<a name="optional-pattern"></a>
|
||||
> *可选模式* → [*标识符模式*](03_Types.html#type-identifier) **?**
|
||||
|
||||
<a name="type-casting_patterns"></a>
|
||||
## 类型转换模式(Type-Casting Patterns)
|
||||
###### optional-pattern {#optional-pattern}
|
||||
> *可选模式* → [*标识符模式*](./03_Types.md#type-identifier) **?**
|
||||
>
|
||||
|
||||
## 类型转换模式(Type-Casting Patterns) {#type-casting_patterns}
|
||||
有两种类型转换模式,`is` 模式和 `as` 模式。`is` 模式只出现在 `switch` 语句中的 `case` 标签中。`is` 模式和 `as` 模式形式如下:
|
||||
|
||||
> is `类型`
|
||||
>
|
||||
> `模式` as `类型`
|
||||
>
|
||||
|
||||
`is` 模式仅当一个值的类型在运行时和 `is` 模式右边的指定类型一致,或者是其子类的情况下,才会匹配这个值。`is` 模式和 `is` 运算符有相似表现,它们都进行类型转换,但是 `is` 模式没有返回类型。
|
||||
|
||||
`as` 模式仅当一个值的类型在运行时和 `as` 模式右边的指定类型一致,或者是其子类的情况下,才会匹配这个值。如果匹配成功,被匹配的值的类型被转换成 `as` 模式右边指定的类型。
|
||||
|
||||
关于使用 `switch` 语句配合 `is` 模式和 `as` 模式来匹配值的例子,请参阅 [Any 和 AnyObject 的类型转换](../chapter2/18_Type_Casting.html#type_casting_for_any_and_anyobject)。
|
||||
关于使用 `switch` 语句配合 `is` 模式和 `as` 模式来匹配值的例子,请参阅 [Any 和 AnyObject 的类型转换](../chapter2/18_Type_Casting.md#type_casting_for_any_and_anyobject)。
|
||||
|
||||
> 类型转换模式语法
|
||||
>
|
||||
<a name="type-casting-pattern"></a>
|
||||
###### type-casting-pattern {#type-casting-pattern}
|
||||
> *类型转换模式* → [*is 模式*](#is-pattern) | [*as 模式*](#as-pattern)
|
||||
<a name="is-pattern"></a>
|
||||
> *is 模式* → **is** [*类型*](03_Types.html#type)
|
||||
<a name="as-pattern"></a>
|
||||
> *as 模式* → [*模式*](#pattern) **as** [*类型*](03_Types.html#type)
|
||||
|
||||
<a name="expression_pattern"></a>
|
||||
## 表达式模式(Expression Pattern)
|
||||
>
|
||||
###### is-pattern {#is-pattern}
|
||||
> *is 模式* → **is** [*类型*](./03_Types.md#type)
|
||||
>
|
||||
###### as-pattern {#as-pattern}
|
||||
> *as 模式* → [*模式*](#pattern) **as** [*类型*](03_Types.md#type)
|
||||
>
|
||||
|
||||
## 表达式模式(Expression Pattern) {#expression_pattern}
|
||||
*表达式模式*代表表达式的值。表达式模式只出现在 `switch` 语句中的 `case` 标签中。
|
||||
|
||||
表达式模式代表的表达式会使用 Swift 标准库中的 `~=` 运算符与输入表达式的值进行比较。如果 `~=` 运算符返回 `true`,则匹配成功。默认情况下,`~=` 运算符使用 `==` 运算符来比较两个相同类型的值。它也可以将一个整型数值与一个 `Range` 实例中的一段整数区间做匹配,正如下面这个例子所示:
|
||||
@ -210,6 +216,7 @@ default:
|
||||
```swift
|
||||
// 重载 ~= 运算符对字符串和整数进行比较
|
||||
func ~=(pattern: String, value: Int) -> Bool {
|
||||
>
|
||||
return pattern == "\(value)"
|
||||
}
|
||||
|
||||
@ -224,5 +231,6 @@ default:
|
||||
|
||||
> 表达式模式语法
|
||||
>
|
||||
<a name="expression-pattern"></a>
|
||||
> *表达式模式* → [*表达式*](04_Expressions.html#expression)
|
||||
###### expression-pattern {#expression-pattern}
|
||||
> *表达式模式* → [*表达式*](./04_Expressions.md#expression)
|
||||
>
|
||||
|
||||
@ -2,18 +2,18 @@
|
||||
|
||||
本节涉及泛型类型、泛型函数以及泛型构造器的参数,包括形参和实参。声明泛型类型、函数或构造器时,须指定相应的类型参数。类型参数相当于一个占位符,当实例化泛型类型、调用泛型函数或泛型构造器时,就用具体的类型实参替代之。
|
||||
|
||||
关于 Swift 语言的泛型概述,请参阅 [泛型](../chapter2/22_Generics.html)。
|
||||
|
||||
<a name="generic_parameter"></a>
|
||||
## 泛型形参子句
|
||||
关于 Swift 语言的泛型概述,请参阅 [泛型](../chapter2/22_Generics.md)。
|
||||
|
||||
## 泛型形参子句 {#generic_parameter}
|
||||
*泛型形参子句*指定泛型类型或函数的类型形参,以及这些参数相关的约束和要求。泛型形参子句用尖括号(`<>`)包住,形式如下:
|
||||
|
||||
> <`泛型形参列表`>
|
||||
>
|
||||
|
||||
泛型形参列表中泛型形参用逗号分开,其中每一个采用以下形式:
|
||||
|
||||
> `类型形参` : `约束`
|
||||
>
|
||||
|
||||
泛型形参由两部分组成:类型形参及其后的可选约束。类型形参只是占位符类型(如 `T`,`U`,`V`,`Key`,`Value` 等)的名字而已。你可以在泛型类型、函数的其余部分或者构造器声明,包括函数或构造器的签名中使用它(以及它的关联类型)。
|
||||
|
||||
@ -21,6 +21,7 @@
|
||||
|
||||
```swift
|
||||
func simpleMax<T: Comparable>(_ x: T, _ y: T) -> T {
|
||||
>
|
||||
if x < y {
|
||||
return y
|
||||
}
|
||||
@ -35,51 +36,64 @@ simpleMax(17, 42) // T 被推断为 Int 类型
|
||||
simpleMax(3.14159, 2.71828) // T 被推断为 Double 类型
|
||||
```
|
||||
|
||||
<a name="where_clauses"></a>
|
||||
### Where 子句
|
||||
|
||||
### Where 子句 {#where_clauses}
|
||||
要想对类型形参及其关联类型指定额外要求,可以在函数体或者类型的大括号之前添加 `where` 子句。`where` 子句由关键字 `where` 及其后的用逗号分隔的一个或多个要求组成。
|
||||
|
||||
> `where` : `类型要求`
|
||||
>
|
||||
|
||||
`where` 子句中的要求用于指明该类型形参继承自某个类或符合某个协议或协议组合。尽管 `where` 子句提供了语法糖使其有助于表达类型形参上的简单约束(如 `<T: Comparable>` 等同于 `<T> where T: Comparable`,等等),但是依然可以用来对类型形参及其关联类型提供更复杂的约束,例如你可以强制形参的关联类型遵守协议,如,`<S: Sequence> where S.Iterator.Element: Equatable` 表示泛型类型 `S` 遵守 `Sequence` 协议并且关联类型 `S.Iterator.Element` 遵守 `Equatable` 协议,这个约束确保队列的每一个元素都是符合 `Equatable` 协议的。
|
||||
>
|
||||
|
||||
也可以用操作符 `==` 来指定两个类型必须相同。例如,泛型形参子句 `<S1: Sequence, S2: Sequence> where S1.Iterator.Element == S2.Iterator.Element` 表示 `S1` 和 `S2` 必须都符合 `SequenceType` 协议,而且两个序列中的元素类型必须相同。
|
||||
>
|
||||
|
||||
当然,替代类型形参的类型实参必须满足所有的约束和要求。
|
||||
|
||||
泛型函数或构造器可以重载,但在泛型形参子句中的类型形参必须有不同的约束或要求,抑或二者皆不同。当调用重载的泛型函数或构造器时,编译器会根据这些约束来决定调用哪个重载函数或构造器。
|
||||
|
||||
更多关于泛型 where 从句的信息和关于泛型函数声明的例子,可以看一看 [泛型 where 子句](https://github.com/numbbbbb/the-swift-programming-language-in-chinese/blob/gh-pages/source/chapter2/22_Generics.html#where_clauses)
|
||||
更多关于泛型 where 从句的信息和关于泛型函数声明的例子,可以看一看 [泛型 where 子句](../chapter2/22_Generics.md#where_clauses)
|
||||
|
||||
> 泛型形参子句语法
|
||||
>
|
||||
<a name="generic-parameter-clause"></a>
|
||||
###### generic-parameter-clause {#generic-parameter-clause}
|
||||
> *泛型形参子句* → **<** [*泛型形参列表*](#generic-parameter-list) [*约束子句*](#requirement-clause)<sub>可选</sub> **>**
|
||||
<a name="generic-parameter-list"></a>
|
||||
>
|
||||
###### generic-parameter-list {#generic-parameter-list}
|
||||
> *泛型形参列表* → [*泛形形参*](#generic-parameter) | [*泛形形参*](#generic-parameter) **,** [*泛型形参列表*](#generic-parameter-list)
|
||||
<a name="generic-parameter"></a>
|
||||
> *泛形形参* → [*类型名称*](03_Types.html#type-name)
|
||||
> *泛形形参* → [*类型名称*](03_Types.html#type-name) **:** [*类型标识符*](03_Types.html#type-identifier)
|
||||
> *泛形形参* → [*类型名称*](03_Types.html#type-name) **:** [*协议合成类型*](03_Types.html#protocol-composition-type)
|
||||
> <a name="requirement-clause"></a>
|
||||
>
|
||||
###### generic-parameter {#generic-parameter}
|
||||
> *泛形形参* → [*类型名称*](./03_Types.md#type-name)
|
||||
>
|
||||
> *泛形形参* → [*类型名称*](./03_Types.md#type-name) **:** [*类型标识符*](./03_Types.md#type-identifier)
|
||||
>
|
||||
> *泛形形参* → [*类型名称*](./03_Types.md#type-name) **:** [*协议合成类型*](./03_Types.md#protocol-composition-type)
|
||||
>
|
||||
> ###### requirement-clause {#requirement-clause}
|
||||
>
|
||||
> *约束子句* → **where** [*约束列表*](#requirement-list)
|
||||
<a name="requirement-list"></a>
|
||||
>
|
||||
###### requirement-list {#requirement-list}
|
||||
> *约束列表* → [*约束*](#requirement) | [*约束*](#requirement) **,** [*约束列表*](#requirement-list)
|
||||
<a name="requirement"></a>
|
||||
>
|
||||
###### requirement {#requirement}
|
||||
> *约束* → [*一致性约束*](#conformance-requirement) | [*同类型约束*](#same-type-requirement)
|
||||
> <a name="conformance-requirement"></a>
|
||||
> *一致性约束* → [*类型标识符*](03_Types.html#type-identifier) **:** [*类型标识符*](03_Types.html#type-identifier)
|
||||
> *一致性约束* → [*类型标识符*](03_Types.html#type-identifier) **:** [*协议合成类型*](03_Types.html#protocol-composition-type)
|
||||
<a name="same-type-requirement"></a>
|
||||
> *同类型约束* → [*类型标识符*](03_Types.html#type-identifier) **==** [*类型*](03_Types.html#type)
|
||||
|
||||
<a name="generic_argument"></a>
|
||||
## 泛型实参子句
|
||||
>
|
||||
> ###### conformance-requirement {#conformance-requirement}
|
||||
>
|
||||
> *一致性约束* → [*类型标识符*](./03_Types.md#type-identifier) **:** [*类型标识符*](./03_Types.md#type-identifier)
|
||||
>
|
||||
> *一致性约束* → [*类型标识符*](./03_Types.md#type-identifier) **:** [*协议合成类型*](./03_Types.md#protocol-composition-type)
|
||||
>
|
||||
###### same-type-requirement {#same-type-requirement}
|
||||
> *同类型约束* → [*类型标识符*](./03_Types.md#type-identifier) **==** [*类型*](./03_Types.md#type)
|
||||
>
|
||||
|
||||
## 泛型实参子句 {#generic_argument}
|
||||
*泛型实参子句*指定泛型类型的类型实参。泛型实参子句用尖括号(`<>`)包住,形式如下:
|
||||
|
||||
> <`泛型实参列表`>
|
||||
>
|
||||
|
||||
泛型实参列表中类型实参用逗号分开。类型实参是实际具体类型的名字,用来替代泛型类型的泛型形参子句中的相应的类型形参。从而得到泛型类型的一个特化版本。例如,Swift 标准库中的泛型字典类型的的简化定义如下:
|
||||
|
||||
@ -95,15 +109,19 @@ struct Dictionary<Key: Hashable, Value>: CollectionType, DictionaryLiteralConver
|
||||
|
||||
```swift
|
||||
let arrayOfArrays: Array<Array<Int>> = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
|
||||
>
|
||||
```
|
||||
|
||||
如 [泛型形参子句](#generic_parameter) 所述,不能用泛型实参子句来指定泛型函数或构造器的类型实参。
|
||||
|
||||
> 泛型实参子句语法
|
||||
>
|
||||
<a name="generic-argument-clause"></a>
|
||||
###### generic-argument-clause {#generic-argument-clause}
|
||||
> *泛型实参子句* → **<** [*泛型实参列表*](#generic-argument-list) **>**
|
||||
<a name="generic-argument-list"></a>
|
||||
>
|
||||
###### generic-argument-list {#generic-argument-list}
|
||||
> *泛型实参列表* → [*泛型实参*](#generic-argument) | [*泛型实参*](#generic-argument) **,** [*泛型实参列表*](#generic-argument-list)
|
||||
<a name="generic-argument"></a>
|
||||
> *泛型实参* → [*类型*](03_Types.html#type)
|
||||
>
|
||||
###### generic-argument {#generic-argument}
|
||||
> *泛型实参* → [*类型*](./03_Types.md#type)
|
||||
>
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user