@ -2,7 +2,7 @@
|
||||
> 校对:[Hawstein](https://github.com/Hawstein)
|
||||
|
||||
# 字符串和字符(Strings and Characters)
|
||||
-----------------
|
||||
---
|
||||
|
||||
本页包含内容:
|
||||
|
||||
@ -11,80 +11,58 @@
|
||||
- [字符串可变性](#string_mutability)
|
||||
- [字符串是值类型](#strings_are_value_types)
|
||||
- [使用字符](#working_with_characters)
|
||||
- [计算字符数量](#counting_characters)
|
||||
- [连接字符串和字符](#concatenating_strings_and_characters)
|
||||
- [字符串插值](#string_interpolation)
|
||||
- [比较字符串](#comparing_strings)
|
||||
- [字符串大小写](#uppercase_and_lowercase_strings)
|
||||
- [Unicode](#unicode)
|
||||
- [计算字符数量](#counting_characters)
|
||||
- [访问和修改字符串](#accessing_and_modifying_a_string)
|
||||
- [比较字符串](#comparing_strings)
|
||||
- [字符串的 Unicode 表示形式](#unicode_representations_of_strings)
|
||||
|
||||
`String`是例如"hello, world","海贼王"这样的有序的`Character`(字符)类型的值的集合,通过`String`类型来表示。
|
||||
|
||||
Swift 的`String`和`Character`类型提供了一个快速的,兼容 Unicode 的方式来处理代码中的文本信息。
|
||||
`String`是例如"hello, world","albatross"这样的有序的`Character`(字符)类型的值的集合,通过`String`类型来表示。
|
||||
Swift 的`String`和`Character`类型提供了一个快速的,兼容 Unicode 的方式来处理代码中的文本。
|
||||
创建和操作字符串的语法与 C 语言中字符串操作相似,轻量并且易读。
|
||||
字符串连接操作只需要简单地通过`+`号将两个字符串相连即可。
|
||||
字符串连接操作只需要简单地通过`+`符号将两个字符串相连即可。
|
||||
与 Swift 中其他值一样,能否更改字符串的值,取决于其被定义为常量还是变量。
|
||||
|
||||
尽管语法简易,但`String`类型是一种快速、现代化的字符串实现。
|
||||
每一个字符串都是由独立编码的 Unicode 字符组成,并提供了以不同 Unicode 表示(representations)来访问这些字符的支持。
|
||||
|
||||
Swift 可以在常量、变量、字面量和表达式中进行字符串插值操作,可以轻松创建用于展示、存储和打印的自定义字符串。
|
||||
每一个字符串都是由编码无关的 Unicode 字符组成,并支持访问字符的多种 Unicode 表示形式(representations)。
|
||||
你也可以在常量、变量、字面量和表达式中进行字符串插值操作,这可以帮助你轻松创建用于展示、存储和打印的自定义字符串。
|
||||
|
||||
> 注意:
|
||||
Swift 的`String`类型与 Foundation `NSString`类进行了无缝桥接。如果您利用 Cocoa 或 Cocoa Touch 中的 Foundation 框架进行工作。所有`NSString` API 都可以调用您创建的任意`String`类型的值。除此之外,还可以使用本章介绍的`String`特性。您也可以在任意要求传入`NSString`实例作为参数的 API 中使用`String`类型的值作为替代。
|
||||
>更多关于在 Foundation 和 Cocoa 中使用`String`的信息请查看 [Using Swift with Cocoa and Objective-C](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/BuildingCocoaApps/index.html#//apple_ref/doc/uid/TP40014216)。
|
||||
> Swift 的`String`类型与 Foundation `NSString`类进行了无缝桥接。就像 [AnyObject](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/TypeCasting.html#//apple_ref/doc/uid/TP40014097-CH22-ID343) 中提到的一样,在使用 Cocoa 中的 Foundation 框架时,您可以将创建的任何字符串的值转换成`NSString`,并调用任意的`NSString` API。您也可以在任意要求传入`NSString`实例作为参数的 API 中用`String`类型的值代替。
|
||||
> 更多关于在 Foundation 和 Cocoa 中使用`String`的信息请查看 *[Using Swift with Cocoa and Objective-C](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/BuildingCocoaApps/index.html#//apple_ref/doc/uid/TP40014216)*。
|
||||
|
||||
|
||||
|
||||
<a name="string_literals"></a>
|
||||
## 字符串字面量(String Literals)
|
||||
|
||||
您可以在您的代码中包含一段预定义的字符串值作为字符串字面量。
|
||||
字符串字面量是由双引号 ("") 包裹着的具有固定顺序的文本字符集。
|
||||
|
||||
字符串字面量可以用于为常量和变量提供初始值。
|
||||
|
||||
```swift
|
||||
let someString = "Some string literal value"
|
||||
```
|
||||
|
||||
您可以在您的代码中包含一段预定义的字符串值作为字符串字面量。字符串字面量是由双引号 ("") 包裹着的具有固定顺序的文本字符集。
|
||||
字符串字面量可以用于为常量和变量提供初始值:
|
||||
```let someString = "Some string literal value"```
|
||||
注意`someString`常量通过字符串字面量进行初始化,Swift 会推断该常量为`String`类型。
|
||||
> 注意:
|
||||
`someString`常量通过字符串字面量进行初始化,Swift 因此推断该常量为`String`类型。
|
||||
> 更多关于在字面量的特殊字符,请查看 [Special Characters in String Literals](#special_characters_in_string_literals) 。
|
||||
|
||||
字符串字面量可以包含以下特殊字符:
|
||||
|
||||
* 转义字符`\0`(空字符)、`\\`(反斜线)、`\t`(水平制表符)、`\n`(换行符)、`\r`(回车符)、`\"`(双引号)、`\'`(单引号)。
|
||||
* Unicode 标量,写成`\u{n}`(u为小写),其中`n`为任意的一到八位十六进制数。
|
||||
|
||||
下面的代码为各种特殊字符的使用示例。
|
||||
`wiseWords`常量包含了两个转移特殊字符 (双括号);
|
||||
`dollarSign`、`blackHeart`和`sparklingHeart`常量演示了三种不同格式的 Unicode 标量:
|
||||
|
||||
```swift
|
||||
let wiseWords = "\"我是要成为海贼王的男人\" - 路飞"
|
||||
// "我是要成为海贼王的男人" - 路飞
|
||||
let dollarSign = "\u{24}" // $, Unicode 标量 U+0024
|
||||
let blackHeart = "\u{2665}" // ♥, Unicode 标量 U+2665
|
||||
let sparklingHeart = "\u{1F496}" // 💖, Unicode 标量 U+1F496
|
||||
```
|
||||
|
||||
<a name="initializing_an_empty_string"></a>
|
||||
## 初始化空字符串 (Initializing an Empty String)
|
||||
|
||||
为了构造一个很长的字符串,可以创建一个空字符串作为初始值。
|
||||
可以将空的字符串字面量赋值给变量,也可以初始化一个新的`String`实例:
|
||||
要创建一个空字符串作为初始值,可以将空的字符串字面量赋值给变量,也可以初始化一个新的`String`实例:
|
||||
|
||||
```swift
|
||||
```
|
||||
var emptyString = "" // 空字符串字面量
|
||||
var anotherEmptyString = String() // 初始化 String 实例
|
||||
var anotherEmptyString = String() // 初始化方法
|
||||
// 两个字符串均为空并等价。
|
||||
```
|
||||
|
||||
您可以通过检查其`Boolean`类型的`isEmpty`属性来判断该字符串是否为空:
|
||||
|
||||
```swift
|
||||
```
|
||||
if emptyString.isEmpty {
|
||||
println("什么都没有")
|
||||
print("Nothing to see here")
|
||||
}
|
||||
// 打印输出:"什么都没有"
|
||||
// 打印输出:"Nothing to see here"
|
||||
```
|
||||
|
||||
<a name="string_mutability"></a>
|
||||
@ -92,7 +70,7 @@ if emptyString.isEmpty {
|
||||
|
||||
您可以通过将一个特定字符串分配给一个变量来对其进行修改,或者分配给一个常量来保证其不会被修改:
|
||||
|
||||
```swift
|
||||
```
|
||||
var variableString = "Horse"
|
||||
variableString += " and carriage"
|
||||
// variableString 现在为 "Horse and carriage"
|
||||
@ -102,18 +80,18 @@ constantString += " and another Highlander"
|
||||
```
|
||||
|
||||
> 注意:
|
||||
在 Objective-C 和 Cocoa 中,您通过选择两个不同的类(`NSString`和`NSMutableString`)来指定该字符串是否可以被修改,Swift 中的字符串是否可以修改仅通过定义的是变量还是常量来决定,实现了多种类型可变性操作的统一。
|
||||
> 在 Objective-C 和 Cocoa 中,您需要通过选择两个不同的类(`NSString`和`NSMutableString`)来指定该字符串是否可以被修改。
|
||||
|
||||
<a name="strings_are_value_types"></a>
|
||||
## 字符串是值类型(Strings Are Value Types)
|
||||
|
||||
Swift 的`String`类型是值类型。
|
||||
如果您创建了一个新的字符串,那么当其进行常量、变量赋值操作或在函数/方法中传递时,会进行值拷贝。
|
||||
如果您创建了一个新的字符串,那么当其进行常量、变量赋值操作,或在函数/方法中传递时,会进行值拷贝。
|
||||
任何情况下,都会对已有字符串值创建新副本,并对该新副本进行传递或赋值操作。
|
||||
值类型在 [结构体和枚举是值类型](09_Classes_and_Structures.html#structures_and_enumerations_are_value_types) 中进行了说明。
|
||||
值类型在 [结构体和枚举是值类型](09_Classes_and_Structures.html#structures_and_enumerations_are_value_types) 中进行了详细描述。
|
||||
|
||||
> 注意:
|
||||
与 Cocoa 中的`NSString`不同,当您在 Cocoa 中创建了一个`NSString`实例,并将其传递给一个函数/方法,或者赋值给一个变量,您传递或赋值的是该`NSString`实例的一个引用,除非您特别要求进行值拷贝,否则字符串不会生成新的副本来进行赋值操作。
|
||||
> 与 Cocoa 中的`NSString`不同,当您在 Cocoa 中创建了一个`NSString`实例,并将其传递给一个函数/方法,或者赋值给一个变量,您传递或赋值的是该`NSString`实例的一个引用,除非您特别要求进行值拷贝,否则字符串不会生成新的副本来进行赋值操作。
|
||||
|
||||
Swift 默认字符串拷贝的方式保证了在函数/方法中传递的是字符串的值。
|
||||
很明显无论该值来自于哪里,都是您独自拥有的。
|
||||
@ -124,13 +102,11 @@ Swift 默认字符串拷贝的方式保证了在函数/方法中传递的是字
|
||||
<a name="working_with_characters"></a>
|
||||
## 使用字符(Working with Characters)
|
||||
|
||||
Swift 的`String`类型表示特定序列的`Character`(字符) 类型值的集合。
|
||||
每一个字符值代表一个 Unicode 字符。
|
||||
您可利用`for-in`循环来遍历字符串中的每一个字符:
|
||||
您可通过`for-in`循环来遍历字符串中的`characters`属性来获取每一个字符的值:
|
||||
|
||||
```swift
|
||||
for character in "Dog!🐶" {
|
||||
println(character)
|
||||
```
|
||||
for character in "Dog!🐶".characters {
|
||||
print(character)
|
||||
}
|
||||
// D
|
||||
// o
|
||||
@ -141,33 +117,26 @@ for character in "Dog!🐶" {
|
||||
|
||||
for-in 循环在 [For Loops](05_Control_Flow.html#for_loops) 中进行了详细描述。
|
||||
|
||||
另外,通过标明一个`Character`类型注解并通过字符字面量进行赋值,可以建立一个独立的字符常量或变量:
|
||||
另外,通过标明一个`Character`类型并用字符字面量进行赋值,可以建立一个独立的字符常量或变量:
|
||||
|
||||
```swift
|
||||
let yenSign: Character = "¥"
|
||||
```
|
||||
|
||||
<a name="counting_characters"></a>
|
||||
## 计算字符数量 (Counting Characters)
|
||||
|
||||
通过调用全局`count(_:)`函数,并将字符串作为参数进行传递,可以获取该字符串的字符数量。
|
||||
|
||||
```swift
|
||||
let unusualMenagerie = "Koala 🐨, Snail 🐌, Penguin 🐧, Dromedary 🐪"
|
||||
println("unusualMenagerie has \(count(unusualMenagerie)) characters")
|
||||
// 打印输出:"unusualMenagerie has 40 characters"
|
||||
let exclamationMark: Charater = "!"
|
||||
```
|
||||
字符串可以通过传递一个值类型为`Charater`的数组作为自变量来初始化:
|
||||
|
||||
> 注意:
|
||||
不同的 Unicode 字符以及相同 Unicode 字符的不同表示方式可能需要不同数量的内存空间来存储。所以 Swift 中的字符在一个字符串中并不一定占用相同的内存空间。因此字符串的长度不得不通过迭代字符串中每一个字符的长度来进行计算。如果您正在处理一个长字符串,需要注意`countElements`函数必须遍历字符串中的字符以精准计算字符串的长度。
|
||||
> 另外需要注意的是通过`countElements`返回的字符数量并不总是与包含相同字符的`NSString`的`length`属性相同。`NSString`的`length`属性是基于利用 UTF-16 表示的十六位代码单元数字,而不是基于 Unicode 字符。为了解决这个问题,`NSString`的`length`属性在被 Swift 的`String`访问时会成为`utf16count`。
|
||||
```
|
||||
let catCharacters: [Character] = ["C", "a", "t", "!", "🐱"]
|
||||
let catString = String(catCharacters)
|
||||
print(catString)
|
||||
// 打印输出:"Cat!🐱"
|
||||
```
|
||||
|
||||
<a name="concatenating_strings_and_characters"></a>
|
||||
## 连接字符串和字符 (Concatenating Strings and Characters)
|
||||
|
||||
字符串可以通过加法运算符(`+`)相加在一起(或称“串联”)并创建一个新的字符串:
|
||||
字符串可以通过加法运算符(`+`)相加在一起(或称“连接”)创建一个新的字符串:
|
||||
|
||||
```swift
|
||||
```
|
||||
let string1 = "hello"
|
||||
let string2 = " there"
|
||||
var welcome = string1 + string2
|
||||
@ -176,33 +145,34 @@ var welcome = string1 + string2
|
||||
|
||||
您也可以通过加法赋值运算符 (`+=`) 将一个字符串添加到一个已经存在字符串变量上:
|
||||
|
||||
```swift
|
||||
```
|
||||
var instruction = "look over"
|
||||
instruction += string2
|
||||
// instruction 现在等于 "look over there"
|
||||
```
|
||||
|
||||
您可以用`append`方法将一个字符附加到一个字符串变量的尾部:
|
||||
|
||||
```
|
||||
你可以用将`append`方法将一个字符附加到一个字符串变量的尾部:
|
||||
|
||||
```swift
|
||||
let exclamationMark: Character = "!"
|
||||
welcome.append(exclamationMark)
|
||||
// welcome 现在等于 "hello there!"
|
||||
```
|
||||
|
||||
> 注意:
|
||||
您不能将一个字符串或者字符添加到一个已经存在的字符变量上,因为字符变量只能包含一个字符。
|
||||
> 您不能将一个字符串或者字符添加到一个已经存在的字符变量上,因为字符变量只能包含一个字符。
|
||||
|
||||
|
||||
<a name="string_interpolation"></a>
|
||||
## 字符串插值 (String Interpolation)
|
||||
|
||||
字符串插值是一种构建新字符串的方式,可以在其中包含常量、变量、字面量和表达式。
|
||||
您插入的字符串字面量的每一项都被包裹在以反斜线为前缀的圆括号中:
|
||||
您插入的字符串字面量的每一项都在以反斜线为前缀的圆括号中:
|
||||
|
||||
```swift
|
||||
```
|
||||
let multiplier = 3
|
||||
let message = "\(multiplier) 乘以 2.5 是 \(Double(multiplier) * 2.5)"
|
||||
// message 是 "3 乘以 2.5 是 7.5"
|
||||
let message = "\(multiplier) times 2.5 is \(Double(multiplier) * 2.5)"
|
||||
// message 是 "3 times 2.5 is 7.5"
|
||||
```
|
||||
|
||||
在上面的例子中,`multiplier`作为`\(multiplier)`被插入到一个字符串字面量中。
|
||||
@ -213,37 +183,240 @@ let message = "\(multiplier) 乘以 2.5 是 \(Double(multiplier) * 2.5)"
|
||||
在这个例子中,表达式写为`\(Double(multiplier) * 2.5)`并包含在字符串字面量中。
|
||||
|
||||
> 注意:
|
||||
插值字符串中写在括号中的表达式不能包含非转义双引号 (`"`) 和反斜杠 (`\`),并且不能包含回车或换行符。
|
||||
> 插值字符串中写在括号中的表达式不能包含非转义双引号 (`"`) 和反斜杠 (`\`),并且不能包含回车或换行符。
|
||||
|
||||
|
||||
<a name="unicode"></a>
|
||||
## Unicode
|
||||
|
||||
Unicode 是一个国际标准,用于文本的编码和表示。
|
||||
它使您可以用标准格式表示来自任意语言几乎所有的字符,并能够对文本文件或网页这样的外部资源中的字符进行读写操作。
|
||||
Swift 的字符串和字符类型是完全兼容 Unicode 标准的。
|
||||
|
||||
<a name="unicode_scalars"></a>
|
||||
### Unicode 标量(Unicode Scalars)
|
||||
|
||||
Swift 的`String`类型是基于 *Unicode 标量* 建立的。
|
||||
Unicode 标量是对应字符的唯一21位数字或者修饰符,例如`U+0061`表示小写的拉丁字母(`LATIN SMALL LETTER A`)("`a`"),`U+1F425`表示小鸡表情(`FRONT-FACING BABY CHICK`) ("`🐥`")
|
||||
> 注意:
|
||||
> Unicode *码位(code poing)* 的范围是`U+0000`到`U+D7FF`或者`U+E000`到`U+10FFFF`。Unicode 标量不包括 Unicode *代理项(surrogate pair)* 码位,其码位范围是`U+D800`到`U+DFFF`。
|
||||
|
||||
注意不是所有的21位 Unicode 标量都代表一个字符,因为有一些标量是保留给未来分配的。已经代表一个典型字符的标量都有自己的名字,例如上面例子中的`LATIN SMALL LETTER A`和`FRONT-FACING BABY CHICK`。
|
||||
|
||||
<a name="special_characters_in_string_literals"></a>
|
||||
### 字符串字面量的特殊字符 (Special Characters in String Literals)
|
||||
|
||||
字符串字面量可以包含以下特殊字符:
|
||||
|
||||
* 转义字符`\0`(空字符)、`\\`(反斜线)、`\t`(水平制表符)、`\n`(换行符)、`\r`(回车符)、`\"`(双引号)、`\'`(单引号)。
|
||||
* Unicode 标量,写成`\u{n}`(u为小写),其中`n`为任意一到八位十六进制数且可用的 Unicode 位码。
|
||||
|
||||
下面的代码为各种特殊字符的使用示例。
|
||||
`wiseWords`常量包含了两个双引号;
|
||||
`dollarSign`、`blackHeart`和`sparklingHeart`常量演示了三种不同格式的 Unicode 标量:
|
||||
|
||||
```
|
||||
let wiseWords = "\"Imagination is more important than knowledge\" - Einstein"
|
||||
// "Imageination is more important than knowledge" - Enistein
|
||||
let dollarSign = "\u{24}" // $, Unicode 标量 U+0024
|
||||
let blackHeart = "\u{2665}" // ♥, Unicode 标量 U+2665
|
||||
let sparklingHeart = "\u{1F496}" // 💖, Unicode 标量 U+1F496
|
||||
```
|
||||
|
||||
<a name="extended_grapheme_clusters"></a>
|
||||
### 可扩展的字形群集(Extended Grapheme Clusters)
|
||||
每一个 Swift 的`Character`类型代表一个可扩展的字形群。
|
||||
一个可扩展的字形群是一个或者更多可生成人类可读的字符 Unicode 标量的有序排列。
|
||||
举个例子,字母 é 可以用单一的 Unicode 标量 é (`LATIN SMALL LETTER E WITH ACUTE`, 或者`U+00E9`)来表示。然而一个标准的字母 e (`LATIN SMALL LETTER E`或者`U+0065`) 加上一个急促重音(`COMBINING ACTUE ACCENT`)的标量(`U+0301`),这样一对标量就表示了同样的字母 é。
|
||||
这个急促重音的标量形象的将 e 转换成了 é。
|
||||
在这两种情况中,字母 é 代表了一个单一的 Swift 的字符串,同时代表了一个可扩展的字形群。
|
||||
在第一种情况,这个字形群包含一个单一标量;而在第二种情况,它是包含两个标量的字形群:
|
||||
|
||||
```
|
||||
let eAcute: Character = "\u{E9}" // é
|
||||
let combinedEAcute: Character = "\u{65}\u{301}" // e 后面加上 ́
|
||||
// eAcute 是 é, combinedEAcute 是 é
|
||||
```
|
||||
|
||||
可扩展的字符群集是一个灵活的方法,用许多复杂的脚本字符表示单一字符。
|
||||
例如,来自朝鲜语字母表的韩语音节能表示为组合或分解的有序排列。
|
||||
在 Swift 都会表示为同一个单一的字符:
|
||||
|
||||
|
||||
```
|
||||
let precomposed: Character = "\u{D55C}" // 한
|
||||
let decomposed: Character = "\u{1112}\u{1161}\u{11AB}" // ᄒ, ᅡ, ᆫ
|
||||
// precomposed 是 한, decomposed 是 한
|
||||
```
|
||||
|
||||
可拓展的字符群集可以使包围记号(例如`COMBINING ENCLOSING CIRCLE`或者`U+20DD`)的标量包围其他 Unicode 标量,作为一个单一的字符:
|
||||
|
||||
```
|
||||
let enclosedEAcute: Character = "\u{E9}\u{20DD}"
|
||||
// enclosedEAcute 是 é⃝
|
||||
```
|
||||
|
||||
局部的指示符号的 Unicode 标量可以组合成一个单一的字符,例如 `REGIONAL INDICATOR SYMBOL LETTER U`(`U+1F1FA`)和`REGIONAL INDICATOR SYMBOL LETTER S`(`U+1F1F8`):
|
||||
|
||||
|
||||
```
|
||||
let regionalIndicatorForUS: Character = "\u{1F1FA}\u{1F1F8}"
|
||||
// regionalIndicatorForUS 是 🇺🇸
|
||||
```
|
||||
|
||||
<a name="counting_characters"></a>
|
||||
## 计算字符数量 (Counting Characters)
|
||||
|
||||
调用字符串的`count`属性,就可以获取一个字符串的字符数量:
|
||||
|
||||
|
||||
```
|
||||
let unusualMenagerie = "Koala 🐨, Snail 🐌, Penguin 🐧, Dromedary 🐪"
|
||||
print("unusualMenagerie has \(unusualMenagerie.characters.count) characters")
|
||||
// 打印输出:"unusualMenagerie has 40 characters"
|
||||
```
|
||||
|
||||
注意在 Swift 中,使用可拓展的字符群集作为字符来连接或改变字符串时,并不一定会更改字符串的字符数量。
|
||||
例如,如果你用四个字符的单词 cafe 初始化一个新的字符串,然后添加一个 `COMBINING ACTUE ACCENT`(`U+0301`)作为字符串的结尾。最终这个字符串的字符数量仍然是4,因为第四个字符是 é ,而不是 e :
|
||||
|
||||
```
|
||||
var word = "cafe"
|
||||
print("the number of characters in \(word) is \(word.characters.count)")
|
||||
// 打印输出 "the number of characters in cafe is 4"
|
||||
word += "\u{301}" // COMBINING ACUTE ACCENT, U+0301
|
||||
print("the number of characters in \(word) is \(word.characters.count)")
|
||||
// 打印输出 "the number of characters in café is 4"
|
||||
```
|
||||
|
||||
> 注意:
|
||||
> 可扩展的字符群集可以组成一个或者多个 Unicode 标量。这意味着不同的字符以及相同字符的不同表示方式可能需要不同数量的内存空间来存储。所以 Swift 中的字符在一个字符串中并不一定占用相同的内存空间数量。因此在没有获取字符串的可扩展的字符群的范围时候,就不能计算出字符串的字符数量。如果您正在处理一个长字符串,需要注意`characters`属性必须遍历全部的 Unicode 标量,来确定字符串的字符数量。
|
||||
> 另外需要注意的是通过`characters`返回的字符数量并不总是与包含相同字符的`NSString`的`length`属性相同。`NSString`的`length`属性是利用 UTF-16 表示的十六位代码单元数字,而不是 Unicode 可扩展的字符群集。
|
||||
|
||||
|
||||
<a name="accessing_and_modifying_a_string"></a>
|
||||
## 访问和修改字符串 (Accessing and Modifying a String)
|
||||
你可以通字符串的属性和方法来访问和读取一个它,当然也可以用下标语法完成。
|
||||
|
||||
<a name="string_indices"></a>
|
||||
### 字符串索引 (String Indices)
|
||||
每一个字符串都有一个关联的索引(*index*)类型,`String.index`,它对应着字符串中的每一个字符的位置。
|
||||
前面提到,不同的字符可能会占用不同的内存空间数量,所以要知道字符的确定位置,就必须从字符串开头遍历每一个 Unicode 标量到字符串结尾。因此,Swift 的字符串不能用整数(integer)做索引。
|
||||
使用`startIndex`属性可以获取字符串的第一个字符。使用`endIndex`属性可以获取最后一个字符的末尾位置。如果字符串是空值,`startIndex`和`endIndex`是相等的。
|
||||
通过调用`String.Index`的`predecessor()`方法,可以立即得到前面一个索引,调用`successor()`方法可以立即得到后面一个索引。任何一个字符串的索引都可以通过锁链作用的这些方法来获取另一个索引,也可以调用`advance(start:n:)`函数来获取。但如果尝试获取出界的字符串索引,就会抛出一个运行时错误。
|
||||
你可以使用下标语法来访问字符在字符串的确切索引。尝试获取出界的字符串索引,仍然抛出一个运行时错误。
|
||||
|
||||
```
|
||||
let greeting = "Guten Tag"
|
||||
greeting[greeting.startIndex]
|
||||
// G
|
||||
greeting[greeting.endIndex.predecessor()]
|
||||
// g
|
||||
greeting[greeting.startIndex.successor()]
|
||||
// u
|
||||
let index = advance(greeting.startIndex, 7)
|
||||
greeting[index]
|
||||
// a
|
||||
greeting[greeting.endIndex] // 错误
|
||||
greeting.endIndex.successor() // 错误
|
||||
```
|
||||
|
||||
使用`characters`属性的`indices`会创建一个包含全部索引的范围(`Range`),用来在一个字符串中访问分立的字符。
|
||||
|
||||
```
|
||||
for index in greeting.characters.indices {
|
||||
print("\(greeting[index]) ", appendNewline: false)
|
||||
}
|
||||
// 打印输出 "G u t e n T a g !"
|
||||
```
|
||||
|
||||
<a name="inserting_and_removing"></a>
|
||||
### 插入和删除 (Inserting and Removing)
|
||||
调用`insert(_:atIndex:)`方法可以在一个字符串的指定索引插入一个字符。
|
||||
|
||||
```
|
||||
var welcome = "hello"
|
||||
welcome.insert("!", atIndex: welcome.endIndex)
|
||||
// welcome now 现在等于 "hello!"
|
||||
```
|
||||
|
||||
调用`splice(_:atIndex:)`方法可以在一个字符串的指定索引插入一个字符串。
|
||||
|
||||
```
|
||||
welcome.splice(" there".characters, atIndex: welcome.endIndex.predecessor())
|
||||
// welcome 现在等于 "hello there!"
|
||||
```
|
||||
|
||||
调用`removeAtIndex(_:)`方法可以在一个字符串的指定索引删除一个字符。
|
||||
|
||||
```
|
||||
welcome.removeAtIndex(welcome.endIndex.predecessor())
|
||||
// welcome 现在等于 "hello there"
|
||||
// 翻译的人解释:最后还有一个换行符,所以这里删除的是 !
|
||||
```
|
||||
|
||||
调用`removeRange(_:)`方法可以在一个字符串的指定索引删除一个子字符串。
|
||||
|
||||
```
|
||||
let range = advance(welcome.endIndex, -6)..<welcome.endIndex
|
||||
welcome.removeRange(range)
|
||||
// welcome 现在等于 "hello"
|
||||
```
|
||||
|
||||
|
||||
<a name="comparing_strings"></a>
|
||||
## 比较字符串 (Comparing Strings)
|
||||
|
||||
Swift 提供了三种方式来比较字符串的值:字符串相等、前缀相等和后缀相等。
|
||||
Swift 提供了三种方式来比较文本值:字符串字符相等、前缀相等和后缀相等。
|
||||
|
||||
<a name="string_equality"></a>
|
||||
### 字符串相等 (String Equality)
|
||||
<a name="string_and_character_equality"></a>
|
||||
### 字符串/字符相等 (String and Character Equality)
|
||||
字符串/字符可以用等于操作符(`==`)和不等于操作符(`!=`),详细描述在 [Comparison Operators](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/BasicOperators.html#//apple_ref/doc/uid/TP40014097-CH6-ID70):
|
||||
|
||||
如果两个字符串以同一顺序包含完全相同的字符,则认为两者字符串相等:
|
||||
|
||||
```swift
|
||||
let quotation = "我们是一样一样滴."
|
||||
let sameQuotation = "我们是一样一样滴."
|
||||
if quotation == sameQuotation {
|
||||
println("这两个字符串被认为是相同的")
|
||||
}
|
||||
// 打印输出:"这两个字符串被认为是相同的"
|
||||
```
|
||||
let quotation = "We're a lot alike, you and I."
|
||||
let sameQuotation = "We're a lot alike, you and I."
|
||||
if quotation == sameQuotation {
|
||||
print("These two strings are considered equal")
|
||||
}
|
||||
// 打印输出 "These two strings are considered equal"
|
||||
```
|
||||
|
||||
如果两个字符串(或者两个字符)的可扩展的字形群集是标准相等的,那就认为它们是相等的。在这个情况下,即使可扩展的字形群集是有不同的 Unicode 标量构成的,只要它们有同样的语言意义和外观,就认为它们标准相等。
|
||||
例如,`LATIN SMALL LETTER E WITH ACUTE`(`U+00E9`)就是标准相等于`LATIN SMALL LETTER E`(`U+0065`)后面加上`COMBINING ACUTE ACCENT`(`U+0301`)。这两个字符群集都有效的表示字符 é ,所以它们被认为是标准相等的:
|
||||
|
||||
```
|
||||
// "Voulez-vous un café?" 使用 LATIN SMALL LETTER E WITH ACUTE
|
||||
let eAcuteQuestion = "Voulez-vous un caf\u{E9}?"
|
||||
// "Voulez-vous un café?" 使用 LATIN SMALL LETTER E and COMBINING ACUTE ACCENT
|
||||
let combinedEAcuteQuestion = "Voulez-vous un caf\u{65}\u{301}?"
|
||||
if eAcuteQuestion == combinedEAcuteQuestion {
|
||||
print("These two strings are considered equal")
|
||||
}
|
||||
// 打印输出 "These two strings are considered equal"
|
||||
```
|
||||
|
||||
相反,英语中的`LATIN CAPITAL LETTER A`(`U+0401`,或者`A`)不等于俄语中的`CYRILLIC CAPITAL LETTER A`(`U+0410`,或者`A`)。两个字符看着是一样的,但却有不同的语言意义:
|
||||
|
||||
```
|
||||
let latinCapitalLetterA: Character = "\u{41}"
|
||||
let cyrillicCapitalLetterA: Character = "\u{0410}"
|
||||
if latinCapitalLetterA != cyrillicCapitalLetterA {
|
||||
print("These two characters are not equivalent")
|
||||
}
|
||||
// 打印 "These two characters are not equivalent"
|
||||
```
|
||||
|
||||
> 注意:
|
||||
> 在 Swift 中,字符串和字符并不区分区域。
|
||||
|
||||
|
||||
<a name="prefix_and_suffix_equality"></a>
|
||||
### 前缀/后缀相等 (Prefix and Suffix Equality)
|
||||
|
||||
通过调用字符串的`hasPrefix`/`hasSuffix`方法来检查字符串是否拥有特定前缀/后缀。
|
||||
两个方法均需要以字符串作为参数传入并传出`Boolean`值。
|
||||
两个方法均执行基本字符串和前缀/后缀字符串之间逐个字符的比较操作。
|
||||
|
||||
通过调用字符串的`hasPrefix(_:)`/`hasSuffix(_:)`方法来检查字符串是否拥有特定前缀/后缀,两个方法均需要以字符串作为参数传入并传出`Boolean`值。
|
||||
下面的例子以一个字符串数组表示莎士比亚话剧《罗密欧与朱丽叶》中前两场的场景位置:
|
||||
|
||||
```swift
|
||||
```
|
||||
let romeoAndJuliet = [
|
||||
"Act 1 Scene 1: Verona, A public place",
|
||||
"Act 1 Scene 2: Capulet's mansion",
|
||||
@ -259,22 +432,22 @@ let romeoAndJuliet = [
|
||||
]
|
||||
```
|
||||
|
||||
您可以利用`hasPrefix`方法来计算话剧中第一幕的场景数:
|
||||
您可以调用`hasPrefix(_:)`方法来计算话剧中第一幕的场景数:
|
||||
|
||||
```swift
|
||||
```
|
||||
var act1SceneCount = 0
|
||||
for scene in romeoAndJuliet {
|
||||
if scene.hasPrefix("Act 1 ") {
|
||||
++act1SceneCount
|
||||
}
|
||||
}
|
||||
println("There are \(act1SceneCount) scenes in Act 1")
|
||||
// 打印输出:"There are 5 scenes in Act 1"
|
||||
print("There are \(act1SceneCount) scenes in Act 1")
|
||||
// 打印输出 "There are 5 scenes in Act 1"
|
||||
```
|
||||
|
||||
相似地,您可以用`hasSuffix`方法来计算发生在不同地方的场景数:
|
||||
相似地,您可以用`hasSuffix(_:)`方法来计算发生在不同地方的场景数:
|
||||
|
||||
```swift
|
||||
```
|
||||
var mansionCount = 0
|
||||
var cellCount = 0
|
||||
for scene in romeoAndJuliet {
|
||||
@ -284,127 +457,208 @@ for scene in romeoAndJuliet {
|
||||
++cellCount
|
||||
}
|
||||
}
|
||||
println("\(mansionCount) mansion scenes; \(cellCount) cell scenes")
|
||||
// 打印输出:"6 mansion scenes; 2 cell scenes"
|
||||
print("\(mansionCount) mansion scenes; \(cellCount) cell scenes")
|
||||
// 打印输出 "6 mansion scenes; 2 cell scenes"
|
||||
```
|
||||
|
||||
<a name="uppercase_and_lowercase_strings"></a>
|
||||
### 大写和小写字符串(Uppercase and Lowercase Strings)
|
||||
> 注意:
|
||||
> `hasPrefix(_:)`和`hasSuffix(_:)`方法都是在每个字符串中一个一个字符的比较其可扩展的字符群集是否标准相等,详细描述在[字符串/字符相等](#string_and_character_equality)。
|
||||
|
||||
您可以通过字符串的`uppercaseString`和`lowercaseString`属性来访问大写/小写版本的字符串。
|
||||
|
||||
```swift
|
||||
import Foundation
|
||||
|
||||
let normal = "Could you help me, please?"
|
||||
let shouty = normal.uppercaseString
|
||||
// shouty 值为 "COULD YOU HELP ME, PLEASE?"
|
||||
let whispered = normal.lowercaseString
|
||||
// whispered 值为 "could you help me, please?"
|
||||
```
|
||||
|
||||
<a name="unicode"></a>
|
||||
## Unicode
|
||||
|
||||
Unicode 是一个国际标准,用于文本的编码和表示。
|
||||
它使您可以用标准格式表示来自任意语言几乎所有的字符,并能够对文本文件或网页这样的外部资源中的字符进行读写操作。
|
||||
|
||||
Swift 的字符串和字符类型是完全兼容 Unicode 标准的,它支持如下所述的一系列不同的 Unicode 编码。
|
||||
|
||||
<a name="unicode_terminology"></a>
|
||||
### Unicode 术语(Unicode Terminology)
|
||||
|
||||
Unicode 中每一个字符都可以被解释为一个或多个 unicode 标量。
|
||||
字符的 unicode 标量是一个唯一的21位数字(和名称),例如`U+0061`表示小写的拉丁字母A ("a"),`U+1F425`表示小鸡表情 ("🐥")
|
||||
|
||||
当 Unicode 字符串被写进文本文件或其他存储结构当中,这些 unicode 标量将会按照 Unicode 定义的集中格式之一进行编码。其包括`UTF-8`(以8位代码单元进行编码) 和`UTF-16`(以16位代码单元进行编码)。
|
||||
|
||||
<a name="unicode_representations_of_strings"></a>
|
||||
### 字符串的 Unicode 表示(Unicode Representations of Strings)
|
||||
## 字符串的 Unicode 表示形式(Unicode Representations of Strings)
|
||||
当一个 Unicode 字符串被写进文本文件或者其他储存时,字符串中的 Unicode 标量会用 Unicode 定义的几种编码格式编码。每一个字符串中的小块编码都被称为代码单元。这些包括 UTF-8 编码格式(编码字符串为8位的代码单元), UTF-16 编码格式(编码字符串位16位的代码单元),以及 UTF-32 编码格式(编码字符串32位的代码单元)。
|
||||
|
||||
Swift 提供了几种不同的方式来访问字符串的 Unicode 表示。
|
||||
|
||||
您可以利用`for-in`来对字符串进行遍历,从而以 Unicode 字符的方式访问每一个字符值。
|
||||
Swift 提供了几种不同的方式来访问字符串的 Unicode 表示形式。
|
||||
您可以利用`for-in`来对字符串进行遍历,从而以 Unicode 可扩展的字符群集的方式访问每一个字符值。
|
||||
该过程在 [使用字符](#working_with_characters) 中进行了描述。
|
||||
|
||||
另外,能够以其他三种 Unicode 兼容的方式访问字符串的值:
|
||||
|
||||
* UTF-8 代码单元集合 (利用字符串的`utf8`属性进行访问)
|
||||
* UTF-16 代码单元集合 (利用字符串的`utf16`属性进行访问)
|
||||
* 21位的 Unicode 标量值集合 (利用字符串的`unicodeScalars`属性进行访问)
|
||||
* 21位的 Unicode 标量值集合,也就是字符串的 UTF-32 编码格式 (利用字符串的`unicodeScalars`属性进行访问)
|
||||
|
||||
下面由`D``o``g``!`和`🐶`(`DOG FACE`,Unicode 标量为`U+1F436`)组成的字符串中的每一个字符代表着一种不同的表示:
|
||||
下面由`D``o``g``‼`(`DOUBLE EXCLAMATION MARK`, Unicode 标量 `U+203C`)和`🐶`(`DOG FACE`,Unicode 标量为`U+1F436`)组成的字符串中的每一个字符代表着一种不同的表示:
|
||||
|
||||
```swift
|
||||
let dogString = "Dog!🐶"
|
||||
```
|
||||
let dogString = "Dog‼🐶"
|
||||
```
|
||||
|
||||
<a name="UTF-8"></a>
|
||||
### UTF-8
|
||||
|
||||
<a name="UTF-8_representation"></a>
|
||||
### UTF-8 表示
|
||||
您可以通过遍历字符串的`utf8`属性来访问它的`UTF-8`表示。
|
||||
其为`UTF8View`类型的属性,`UTF8View`是无符号8位 (`UInt8`) 值的集合,每一个`UInt8`值都是一个字符的 UTF-8 表示:
|
||||
其为`String.UTF8View`类型的属性,`UTF8View`是无符号8位 (`UInt8`) 值的集合,每一个`UInt8`值都是一个字符的 UTF-8 表示:
|
||||
|
||||
```swift
|
||||
<body>
|
||||
<center>
|
||||
<table style='text-align:center'>
|
||||
<tr height=77>
|
||||
<td>Character</td>
|
||||
<td>D<br>U+0044</td>
|
||||
<td>o<br>U+006F</td>
|
||||
<td>g<br>U+0067</td>
|
||||
<td colspan=3>‼<br>U+1F436</td>
|
||||
<td colspan=4>🐶<br>U+1F436</td>
|
||||
</tr>
|
||||
<tr height=77>
|
||||
<td height=77>UTF-8<br>Code Unit</td>
|
||||
<td>68</td>
|
||||
<td>111</td>
|
||||
<td>103</td>
|
||||
<td>226</td>
|
||||
<td>128</td>
|
||||
<td>188</td>
|
||||
<td>240</td>
|
||||
<td>159</td>
|
||||
<td>144</td>
|
||||
<td>182</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td height=77>Position</td>
|
||||
<td>0</td>
|
||||
<td>1</td>
|
||||
<td>2</td>
|
||||
<td>3</td>
|
||||
<td>4</td>
|
||||
<td>5</td>
|
||||
<td>6</td>
|
||||
<td>7</td>
|
||||
<td>8</td>
|
||||
<td>9</td>
|
||||
</tr>
|
||||
</table>
|
||||
</center>
|
||||
</body>
|
||||
|
||||
```
|
||||
for codeUnit in dogString.utf8 {
|
||||
print("\(codeUnit) ")
|
||||
print("\(codeUnit) ", appendNewline: false)
|
||||
}
|
||||
print("\n")
|
||||
// 68 111 103 33 240 159 144 182
|
||||
print("")
|
||||
// 68 111 103 226 128 188 240 159 144 182
|
||||
```
|
||||
|
||||
上面的例子中,前四个10进制代码单元值 (68, 111, 103, 33) 代表了字符`D` `o` `g`和`!`,它们的 UTF-8 表示与 ASCII 表示相同。
|
||||
后四个代码单元值 (240, 159, 144, 182) 是`DOG FACE`的4字节 UTF-8 表示。
|
||||
上面的例子中,前三个10进制代码单元值 (68, 111, 103) 代表了字符`D`、`o`和 `g`,它们的 UTF-8 表示与 ASCII 表示相同。
|
||||
接下来的三个10进制代码单元值 (226, 128, 188) 是`DOUBLE EXCLAMATION MARK`的3字节 UTF-8 表示。
|
||||
最后的四个代码单元值 (240, 159, 144, 182) 是`DOG FACE`的4字节 UTF-8 表示。
|
||||
|
||||
<a name="UTF-16"></a>
|
||||
### UTF-16
|
||||
|
||||
<a name="UTF-16_representation"></a>
|
||||
### UTF-16 表示
|
||||
|
||||
您可以通过遍历字符串的`utf16`属性来访问它的`UTF-16`表示。
|
||||
其为`UTF16View`类型的属性,`UTF16View`是无符号16位 (`UInt16`) 值的集合,每一个`UInt16`都是一个字符的 UTF-16 表示:
|
||||
其为`String.UTF16View`类型的属性,`UTF16View`是无符号16位 (`UInt16`) 值的集合,每一个`UInt16`都是一个字符的 UTF-16 表示:
|
||||
<body>
|
||||
<center>
|
||||
<table style='text-align:center'>
|
||||
<tr height=77>
|
||||
<td>Character</td>
|
||||
<td>D<br>U+0044</td>
|
||||
<td>o<br>U+006F</td>
|
||||
<td>g<br>U+0067</td>
|
||||
<td>‼<br>U+1F436</td>
|
||||
<td colspan=2>🐶<br>U+1F436</td>
|
||||
</tr>
|
||||
<tr height=77>
|
||||
<td height=77>UTF-16<br>Code Unit</td>
|
||||
<td>68</td>
|
||||
<td>111</td>
|
||||
<td>103</td>
|
||||
<td>8252</td>
|
||||
<td>55357</td>
|
||||
<td>56374</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td height=77>Position</td>
|
||||
<td>0</td>
|
||||
<td>1</td>
|
||||
<td>2</td>
|
||||
<td>3</td>
|
||||
<td>4</td>
|
||||
<td>5</td>
|
||||
</tr>
|
||||
</table>
|
||||
</center>
|
||||
</body>
|
||||
|
||||
```swift
|
||||
|
||||
```
|
||||
for codeUnit in dogString.utf16 {
|
||||
print("\(codeUnit) ")
|
||||
print("\(codeUnit) ", appendNewline: false)
|
||||
}
|
||||
print("\n")
|
||||
// 68 111 103 33 55357 56374
|
||||
print("")
|
||||
// 68 111 103 8252 55357 56374
|
||||
```
|
||||
|
||||
同样,前四个代码单元值 (68, 111, 103, 33) 代表了字符`D` `o` `g`和`!`,它们的 UTF-16 代码单元和 UTF-8 完全相同。
|
||||
|
||||
同样,前三个代码单元值 (68, 111, 103) 代表了字符`D`、`o`和`g`,它们的 UTF-16 代码单元和 UTF-8 完全相同(因为这些 Unicode 标量表示 ASCII 字符)。
|
||||
第四个代码单元值 (8252) 是一个等于十六进制203C的的十进制值。这个代表了`DOUBLE EXCLAMATION MARK`字符的 Unicode 标量值`U+203C`。这个字符在 UTF-16 中可以用一个代码单元表示。
|
||||
第五和第六个代码单元值 (55357 和 56374) 是`DOG FACE`字符的UTF-16 表示。
|
||||
第一个值为`U+D83D`(十进制值为 55357),第二个值为`U+DC36`(十进制值为 56374)。
|
||||
|
||||
<a name="unicode_scalars"></a>
|
||||
### Unicode 标量 (Unicode Scalars)
|
||||
<a name="unicode_scalars_representation"></a>
|
||||
### Unicode 标量表示 (Unicode Scalars Representation)
|
||||
|
||||
您可以通过遍历字符串的`unicodeScalars`属性来访问它的 Unicode 标量表示。
|
||||
其为`UnicodeScalarView`类型的属性, `UnicodeScalarView`是`UnicodeScalar`的集合。
|
||||
`UnicodeScalar`是21位的 Unicode 代码点。
|
||||
|
||||
每一个`UnicodeScalar`拥有一个值属性,可以返回对应的21位数值,用`UInt32`来表示。
|
||||
每一个`UnicodeScalar`拥有一个值属性,可以返回对应的21位数值,用`UInt32`来表示:
|
||||
|
||||
```swift
|
||||
<body>
|
||||
<center>
|
||||
<table style='text-align:center'>
|
||||
<tr height=77>
|
||||
<td>Character</td>
|
||||
<td>D<br>U+0044</td>
|
||||
<td>o<br>U+006F</td>
|
||||
<td>g<br>U+0067</td>
|
||||
<td>‼<br>U+1F436</td>
|
||||
<td>🐶<br>U+1F436</td>
|
||||
</tr>
|
||||
<tr height=77>
|
||||
<td height=77>UTF-16<br>Code Unit</td>
|
||||
<td>68</td>
|
||||
<td>111</td>
|
||||
<td>103</td>
|
||||
<td>8252</td>
|
||||
<td>128054</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td height=77>Position</td>
|
||||
<td>0</td>
|
||||
<td>1</td>
|
||||
<td>2</td>
|
||||
<td>3</td>
|
||||
<td>4</td>
|
||||
</tr>
|
||||
</table>
|
||||
</center>
|
||||
</body>
|
||||
|
||||
|
||||
```
|
||||
for scalar in dogString.unicodeScalars {
|
||||
print("\(scalar.value) ")
|
||||
print("\(scalar.value) ", appendNewline: false)
|
||||
}
|
||||
print("\n")
|
||||
// 68 111 103 33 128054
|
||||
print("")
|
||||
// 68 111 103 8252 128054
|
||||
```
|
||||
|
||||
同样,前四个代码单元值 (68, 111, 103, 33) 代表了字符`D` `o` `g`和`!`。
|
||||
第五位数值,128054,是一个十六进制1F436的十进制表示。
|
||||
其等同于`DOG FACE`的Unicode 标量 U+1F436。
|
||||
前三个代码单元值 (68, 111, 103) 仍然代表字符`D`、`o`和`g`。
|
||||
第四个代码单元值 (8252) 仍然是一个等于十六进制203C的的十进制值。这个代表了`DOUBLE EXCLAMATION MARK`字符的 Unicode 标量`U+203C`。
|
||||
第五位数值,128054,是一个十六进制1F436的十进制表示。其等同于`DOG FACE`的Unicode 标量`U+1F436`。
|
||||
|
||||
作为查询字符值属性的一种替代方法,每个`UnicodeScalar`值也可以用来构建一个新的字符串值,比如在字符串插值中使用:
|
||||
|
||||
```swift
|
||||
```
|
||||
for scalar in dogString.unicodeScalars {
|
||||
println("\(scalar) ")
|
||||
print("\(scalar) ")
|
||||
}
|
||||
// D
|
||||
// o
|
||||
// g
|
||||
// !
|
||||
// ‼
|
||||
// 🐶
|
||||
```
|
||||
|
||||
@ -11,20 +11,20 @@
|
||||
- [相关值(Associated Values)](#associated_values)
|
||||
- [原始值(Raw Values)](#raw_values)
|
||||
|
||||
枚举定义了一个通用类型的一组相关的值,使你可以在你的代码中以一个安全的方式来使用这些值。
|
||||
*枚举*定义了一个通用类型的一组相关值,使你可以在你的代码中以一种安全的方式来使用这些值。
|
||||
|
||||
如果你熟悉 C 语言,你就会知道,在 C 语言中枚举指定相关名称为一组整型值。Swift 中的枚举更加灵活,不必给每一个枚举成员提供一个值。如果一个值(被认为是“原始”值)被提供给每个枚举成员,则该值可以是一个字符串,一个字符,或是一个整型值或浮点值。
|
||||
如果你熟悉 C 语言,你就会知道,在 C 语言中枚举将枚举名和一个整型值相对应。Swift 中的枚举更加灵活,不必给每一个枚举成员提供一个值。如果给枚举成员提供一个值(称为“原始”值),则该值的类型可以是字符串,字符,或是一个整型值或浮点数。
|
||||
|
||||
此外,枚举成员可以指定任何类型的相关值存储到枚举成员值中,就像其他语言中的联合体(unions)和变体(variants)。你可以定义一组通用的相关成员作为枚举的一部分,每一组都有不同的一组与它相关的适当类型的数值。
|
||||
|
||||
在 Swift 中,枚举类型是一等(first-class)类型。它们采用了很多传统上只被类(class)所支持的特征,例如计算型属性(computed properties),用于提供关于枚举当前值的附加信息, 实例方法(instance methods),用于提供和枚举所代表的值相关联的功能。枚举也可以定义构造函数(initializers)来提供一个初始成员值;可以在原始的实现基础上扩展它们的功能;可以遵守协议(protocols)来提供标准的功能。
|
||||
在 Swift 中,枚举类型是一等公民(first-class)。它们采用了很多传统上只被类(class)所支持的特征,例如计算型属性(computed properties),用于提供关于枚举当前值的附加信息, 实例方法(instance methods),用于提供和枚举所代表的值相关联的功能。枚举也可以定义构造函数(initializers)来提供一个初始值;可以在原始的实现基础上扩展它们的功能;可以遵守协议(protocols)来提供标准的功能。
|
||||
|
||||
欲了解更多相关功能,请参见[属性(Properties)](10_Properties.html),[方法(Methods)](11_Methods.html),[构造过程(Initialization)](14_Initialization.html),[扩展(Extensions)](20_Extensions.html)和[协议(Protocols)](21_Protocols.html)。
|
||||
欲了解更多相关信息,请参见[属性(Properties)](10_Properties.html),[方法(Methods)](11_Methods.html),[构造过程(Initialization)](14_Initialization.html),[扩展(Extensions)](20_Extensions.html)和[协议(Protocols)](21_Protocols.html)。
|
||||
|
||||
<a name="enumeration_syntax"></a>
|
||||
## 枚举语法
|
||||
|
||||
使用`enum`关键词并且把它们的整个定义放在一对大括号内:
|
||||
使用`enum`关键词来创建枚举并且把它们的整个定义放在一对大括号内:
|
||||
|
||||
```swift
|
||||
enum SomeEnumeration {
|
||||
@ -43,10 +43,10 @@ enum CompassPoint {
|
||||
}
|
||||
```
|
||||
|
||||
一个枚举中被定义的值(例如 `North`,`South`,`East`和`West`)是枚举的***成员值***(或者***成员***)。`case`关键词表明新的一行成员值将被定义。
|
||||
一个枚举中被定义的值(例如 `North`,`South`,`East`和`West`)是枚举的*成员值*(或者*成员*)。`case`关键词表明新的一行成员值将被定义。
|
||||
|
||||
> 注意:
|
||||
> 不像 C 和 Objective-C 一样,Swift 的枚举成员在被创建时不会被赋予一个默认的整数值。在上面的`CompassPoints`例子中,`North`,`South`,`East`和`West`不是隐式的等于`0`,`1`,`2`和`3`。相反的,这些不同的枚举成员在`CompassPoint`的一种显示定义中拥有各自不同的值。
|
||||
> 和 C 和 Objective-C 不同,Swift 的枚举成员在被创建时不会被赋予一个默认的整型值。在上面的`CompassPoints`例子中,`North`,`South`,`East`和`West`不会隐式地赋值为了`0`,`1`,`2`和`3`。相反的,这些不同的枚举成员在`CompassPoint`的一种显示定义中拥有各自不同的值。
|
||||
|
||||
多个成员值可以出现在同一行上,用逗号隔开:
|
||||
|
||||
@ -62,51 +62,51 @@ enum Planet {
|
||||
var directionToHead = CompassPoint.West
|
||||
```
|
||||
|
||||
`directionToHead`的类型被推断当它被`CompassPoint`的一个可能值初始化。一旦`directionToHead`被声明为一个`CompassPoint`,你可以使用更短的点(.)语法将其设置为另一个`CompassPoint`的值:
|
||||
`directionToHead`的类型可以在它被`CompassPoint`的一个可能值初始化时推断出来。一旦`directionToHead`被声明为一个`CompassPoint`,你可以使用一个缩写语法(.)将其设置为另一个`CompassPoint`的值:
|
||||
|
||||
```swift
|
||||
directionToHead = .East
|
||||
```
|
||||
|
||||
`directionToHead`的类型已知时,当设定它的值时,你可以不再写类型名。使用显式类型的枚举值可以让代码具有更好的可读性。
|
||||
当`directionToHead`的类型已知时,再次为其赋值可以省略枚举名。使用显式类型的枚举值可以让代码具有更好的可读性。
|
||||
|
||||
<a name="matching_enumeration_values_with_a_switch_statement"></a>
|
||||
## 匹配枚举值和`Switch`语句
|
||||
|
||||
你可以匹配单个枚举值和`switch`语句:
|
||||
你可以使用`switch`语句匹配单个枚举值:
|
||||
|
||||
```swift
|
||||
directionToHead = .South
|
||||
switch directionToHead {
|
||||
case .North:
|
||||
println("Lots of planets have a north")
|
||||
print("Lots of planets have a north")
|
||||
case .South:
|
||||
println("Watch out for penguins")
|
||||
print("Watch out for penguins")
|
||||
case .East:
|
||||
println("Where the sun rises")
|
||||
print("Where the sun rises")
|
||||
case .West:
|
||||
println("Where the skies are blue")
|
||||
print("Where the skies are blue")
|
||||
}
|
||||
// 输出 "Watch out for penguins”
|
||||
```
|
||||
|
||||
你可以如此理解这段代码:
|
||||
你可以这样理解这段代码:
|
||||
|
||||
“考虑`directionToHead`的值。当它等于`.North`,打印`“Lots of planets have a north”`。当它等于`.South`,打印`“Watch out for penguins”`。”
|
||||
“判断`directionToHead`的值。当它等于`.North`,打印`“Lots of planets have a north”`。当它等于`.South`,打印`“Watch out for penguins”`。”
|
||||
|
||||
等等依次类推。
|
||||
等等以此类推。
|
||||
|
||||
正如在[控制流(Control Flow)](05_Control_Flow.html)中介绍,当考虑一个枚举的成员们时,一个`switch`语句必须全面。如果忽略了`.West`这种情况,上面那段代码将无法通过编译,因为它没有考虑到`CompassPoint`的全部成员。全面性的要求确保了枚举成员不会被意外遗漏。
|
||||
正如在[控制流(Control Flow)](05_Control_Flow.html)中介绍的那样,在判断一个枚举类型的值时,`switch`语句必须穷举所有情况。如果忽略了`.West`这种情况,上面那段代码将无法通过编译,因为它没有考虑到`CompassPoint`的全部成员。强制性全部穷举的要求确保了枚举成员不会被意外遗漏。
|
||||
|
||||
当不需要匹配每个枚举成员的时候,你可以提供一个默认`default`分支来涵盖所有未明确被提出的任何成员:
|
||||
当不需要匹配每个枚举成员的时候,你可以提供一个默认`default`分支来涵盖所有未明确被提出的枚举成员:
|
||||
|
||||
```swift
|
||||
let somePlanet = Planet.Earth
|
||||
switch somePlanet {
|
||||
case .Earth:
|
||||
println("Mostly harmless")
|
||||
print("Mostly harmless")
|
||||
default:
|
||||
println("Not a safe place for humans")
|
||||
print("Not a safe place for humans")
|
||||
}
|
||||
// 输出 "Mostly harmless”
|
||||
```
|
||||
@ -114,11 +114,11 @@ default:
|
||||
<a name="associated_values"></a>
|
||||
## 相关值(Associated Values)
|
||||
|
||||
上一小节的例子演示了一个枚举的成员是如何被定义(分类)的。你可以为`Planet.Earth`设置一个常量或则变量,并且在之后查看这个值。不管怎样,如果有时候能够把其他类型的相关值和成员值一起存储起来会很有用。这能让你存储成员值之外的自定义信息,并且当你每次在代码中使用该成员时允许这个信息产生变化。
|
||||
上一小节的例子演示了如何定义(分类)枚举的成员。你可以为`Planet.Earth`设置一个常量或者变量,并且在赋值之后查看这个值。不管怎样,如果有时候能够把其他类型的*相关值*和成员值一起存储起来会很有用。这能让你存储成员值之外的自定义信息,并且当你每次在代码中使用该成员时允许这个信息产生变化。
|
||||
|
||||
你可以定义 Swift 的枚举存储任何类型的相关值,如果需要的话,每个成员的数据类型可以是各不相同的。枚举的这种特性跟其他语言中的可辨识联合(discriminated unions),标签联合(tagged unions),或者变体(variants)相似。
|
||||
|
||||
例如,假设一个库存跟踪系统需要利用两种不同类型的条形码来跟踪商品。有些商品上标有 UPC-A 格式的一维码,它使用数字 0 到 9。每一个条形码都有一个代表“数字系统”的数字,该数字后接 10 个代表“标识符”的数字。最后一个数字是“检查”位,用来验证代码是否被正确扫描:
|
||||
例如,假设一个库存跟踪系统需要利用两种不同类型的条形码来跟踪商品。有些商品上标有 UPC-A 格式的一维t条形码,它使用数字 0 到 9。每一个条形码都有一个代表“数字系统”的数字,该数字后接 5 个代表“生产代码”的数字,接下来是5位“产品代码”。最后一个数字是“检查”位,用来验证代码是否被正确扫描:
|
||||
|
||||
<img width="252" height="120" alt="" src="https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Art/barcode_UPC_2x.png">
|
||||
|
||||
@ -128,28 +128,28 @@ default:
|
||||
|
||||
对于库存跟踪系统来说,能够把 UPC-A 码作为三个整型值的元组,和把 QR 码作为一个任何长度的字符串存储起来是方便的。
|
||||
|
||||
在 Swift 中,用来定义两种商品条码的枚举是这样子的:
|
||||
在 Swift 中,使用如下方式定义两种商品条码的枚举:
|
||||
|
||||
```swift
|
||||
enum Barcode {
|
||||
case UPCA(Int, Int, Int)
|
||||
case UPCA(Int, Int, Int, Int)
|
||||
case QRCode(String)
|
||||
}
|
||||
```
|
||||
|
||||
以上代码可以这么理解:
|
||||
|
||||
“定义一个名为`Barcode`的枚举类型,它可以是`UPCA`的一个相关值(`Int`,`Int`,`Int`),或者`QRCode`的一个字符串类型(`String`)相关值。”
|
||||
“定义一个名为`Barcode`的枚举类型,它可以是`UPCA`的一个相关值(`Int`,`Int`,`Int`,`Int`),或者是`QRCode`的一个字符串类型(`String`)相关值。”
|
||||
|
||||
这个定义不提供任何`Int`或`String`的实际值,它只是定义了,当`Barcode`常量和变量等于`Barcode.UPCA`或`Barcode.QRCode`时,相关值的类型。
|
||||
|
||||
然后可以使用任何一种条码类型创建新的条码,如:
|
||||
|
||||
```swift
|
||||
var productBarcode = Barcode.UPCA(8, 85909_51226, 3)
|
||||
var productBarcode = Barcode.UPCA(8, 85909, 51226, 3)
|
||||
```
|
||||
|
||||
以上例子创建了一个名为`productBarcode`的新变量,并且赋给它一个`Barcode.UPCA`的相关元组值`(8, 8590951226, 3)`。提供的“标识符”值在整数字中有一个下划线,使其便于阅读条形码。
|
||||
以上例子创建了一个名为`productBarcode`的变量,并且赋给它一个`Barcode.UPCA`的相关元组值`(8, 85909, 51226, 3)`。
|
||||
|
||||
同一个商品可以被分配给一个不同类型的条形码,如:
|
||||
|
||||
@ -163,32 +163,32 @@ productBarcode = .QRCode("ABCDEFGHIJKLMNOP")
|
||||
|
||||
```swift
|
||||
switch productBarcode {
|
||||
case .UPCA(let numberSystem, let identifier, let check):
|
||||
println("UPC-A with value of \(numberSystem), \(identifier), \(check).")
|
||||
case .UPCA(let numberSystem, let manufacturer, let product, let check):
|
||||
print("UPC-A: \(numberSystem), \(manufacturer), \(product), \(check).")
|
||||
case .QRCode(let productCode):
|
||||
println("QR code with value of \(productCode).")
|
||||
print("QR code: \(productCode).")
|
||||
}
|
||||
// 输出 "QR code with value of ABCDEFGHIJKLMNOP.”
|
||||
// 输出 "QR code: ABCDEFGHIJKLMNOP."
|
||||
```
|
||||
|
||||
如果一个枚举成员的所有相关值被提取为常量,或者它们全部被提取为变量,为了简洁,你可以只放置一个`var`或者`let`标注在成员名称前:
|
||||
|
||||
```swift
|
||||
switch productBarcode {
|
||||
case let .UPCA(numberSystem, identifier, check):
|
||||
println("UPC-A with value of \(numberSystem), \(identifier), \(check).")
|
||||
case let .UPCA(numberSystem, manufacturer, product, check):
|
||||
print("UPC-A: \(numberSystem), \(manufacturer), \(product), \(check).")
|
||||
case let .QRCode(productCode):
|
||||
println("QR code with value of \(productCode).")
|
||||
print("QR code: \(productCode).")
|
||||
}
|
||||
// 输出 "QR code with value of ABCDEFGHIJKLMNOP."
|
||||
// 输出 "QR code: ABCDEFGHIJKLMNOP."
|
||||
```
|
||||
|
||||
<a name="raw_values"></a>
|
||||
## 原始值(Raw Values)
|
||||
|
||||
在[Associated Values](#raw_values)小节的条形码例子中演示了一个枚举的成员如何声明它们存储不同类型的相关值。作为相关值的替代,枚举成员可以被默认值(称为原始值)预先填充,其中这些原始值具有相同的类型。
|
||||
在[Associated Values](#raw_values)小节的条形码例子中演示了一个枚举的成员如何声明它们存储不同类型的相关值。作为相关值的另一种选择,枚举成员可以被默认值(称为原始值)赋值,其中这些原始值具有相同的类型。
|
||||
|
||||
这里是一个枚举成员存储原始 ASCII 值的例子:
|
||||
这里是一个枚举成员存储 ASCII 码的例子:
|
||||
|
||||
```swift
|
||||
enum ASCIIControlCharacter: Character {
|
||||
@ -198,11 +198,11 @@ enum ASCIIControlCharacter: Character {
|
||||
}
|
||||
```
|
||||
|
||||
在这里,称为`ASCIIControlCharacter`的枚举的原始值类型被定义为字符型`Character`,并被设置了一些比较常见的 ASCII 控制字符。字符值的描述请详见字符串和字符[`Strings and Characters`](03_Strings_and_Characters.html)部分。
|
||||
在这里,`ASCIIControlCharacter`的枚举类型的原始值类型被定义为字符型`Character`,并被设置了一些比较常见的 ASCII 控制字符。字符值的描述请详见字符串和字符[`Strings and Characters`](03_Strings_and_Characters.html)部分。
|
||||
|
||||
注意,原始值和相关值是不相同的。当你开始在你的代码中定义枚举的时候原始值是被预先填充的值,像上述三个 ASCII 码。对于一个特定的枚举成员,它的原始值始终是相同的。相关值是当你在创建一个基于枚举成员的新常量或变量时才会被设置,并且每次当你这么做得时候,它的值可以是不同的。
|
||||
注意,原始值和相关值是不相同的。原始值是当你开始定义枚举的时候被预先赋予的值,像上述三个 ASCII 码。对于一个特定的枚举成员,它的原始值始终是相同的。相关值在你在创建一个基于枚举成员的常量或变量时才会被设置,并且每次当你创建的时候,它的值可以是不同的。
|
||||
|
||||
原始值可以是字符串,字符,或者任何整型值或浮点型值。每个原始值在它的枚举声明中必须是唯一的。当整型值被用于原始值,如果其他枚举成员没有值时,它们会自动递增。
|
||||
原始值可以是字符串,字符,或者任何整型值或浮点型值。每个原始值在它的枚举声明中必须是唯一的。当使用整型值作为原始值时,如果其他枚举成员没有值,它们会自动递增。
|
||||
|
||||
下面的枚举是对之前`Planet`这个枚举的一个细化,利用原始整型值来表示每个 planet 在太阳系中的顺序:
|
||||
|
||||
@ -212,7 +212,7 @@ enum Planet: Int {
|
||||
}
|
||||
```
|
||||
|
||||
自动递增意味着`Planet.Venus`的原始值是`2`,依次类推。
|
||||
自动递增意味着`Planet.Venus`的原始值是`2`,以此类推。
|
||||
|
||||
使用枚举成员的`rawValue`属性可以访问该枚举成员的原始值:
|
||||
|
||||
@ -220,15 +220,22 @@ enum Planet: Int {
|
||||
let earthsOrder = Planet.Earth.rawValue
|
||||
// earthsOrder is 3
|
||||
```
|
||||
### 使用原始值来初始化(Initializing from a Raw Value)
|
||||
|
||||
通过参数为`rawValue`构造函数创建特定原始值的枚举。这个例子通过原始值`7`识别`Uranus`:
|
||||
如果你使用原始值的方式创建一个枚举类型,这个枚举将自动获得一个包含原始值参数(参数名为rawValue)的构造器并返回相应的枚举类型或者nil。你可以使用这个构造器来创建新的枚举成员。
|
||||
|
||||
下面这个例子通过原始值`7`创建了`Uranus`枚举类型:
|
||||
|
||||
```swift
|
||||
let possiblePlanet = Planet(rawValue: 7)
|
||||
// possiblePlanet is of type Planet? and equals Planet.Uranus
|
||||
```
|
||||
|
||||
然而,并非所有可能的`Int`值都可以找到一个匹配的行星。正因为如此,构造函数可以返回一个***可选***的枚举成员。在上面的例子中,`possiblePlanet`是`Planet?`类型,或“可选的`Planet`”。
|
||||
然而,并非所有可能的`Int`值都可以找到一个匹配的行星。正因为如此,构造函数可以返回一个*可选*的枚举成员。在上面的例子中,`possiblePlanet`是`Planet?`类型,或称为“可选的`Planet`”。
|
||||
|
||||
> 注意:
|
||||
> 使用原始值构造器是可失败构造器,因为并不是所有的原始值都会返回一个对应的枚举成员。欲了解更多相关信息,请参见[可失败构造器(Failable Initializers)](TODO)
|
||||
|
||||
|
||||
如果你试图寻找一个位置为9的行星,通过参数为`rawValue`构造函数返回的可选`Planet`值将是`nil`:
|
||||
|
||||
@ -237,15 +244,14 @@ let positionToFind = 9
|
||||
if let somePlanet = Planet(rawValue: positionToFind) {
|
||||
switch somePlanet {
|
||||
case .Earth:
|
||||
println("Mostly harmless")
|
||||
print("Mostly harmless")
|
||||
default:
|
||||
println("Not a safe place for humans")
|
||||
print("Not a safe place for humans")
|
||||
}
|
||||
} else {
|
||||
println("There isn't a planet at position \(positionToFind)")
|
||||
print("There isn't a planet at position \(positionToFind)")
|
||||
}
|
||||
// 输出 "There isn't a planet at position 9
|
||||
```
|
||||
|
||||
这个范例使用可选绑定(optional binding),通过原始值`9`试图访问一个行星。`if let somePlanet = Planet(rawValue: 9)`语句获得一个可选`Planet`,如果可选`Planet`可以被获得,把`somePlanet`设置成该可选`Planet`的内容。在这个范例中,无法检索到位置为`9`的行星,所以`else`分支被执行。
|
||||
|
||||
这个范例使用可选绑定(optional binding),通过原始值`9`试图取得一个行星的引用。`if let somePlanet = Planet(rawValue: 9)`语句获得一个可选`Planet`,如果可选`Planet`可以被获得,把`somePlanet`设置成该可选`Planet`的内容。在这个范例中,无法检索到位置为`9`的行星,所以`else`分支被执行。
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
> 翻译:[shinyzhu](https://github.com/shinyzhu)
|
||||
> 校对:[pp-prog](https://github.com/pp-prog)
|
||||
> 校对:[pp-prog](https://github.com/pp-prog) [yangsiy](https://github.com/yangsiy)
|
||||
|
||||
# 属性 (Properties)
|
||||
---
|
||||
@ -12,16 +12,16 @@
|
||||
- [全局变量和局部变量(Global and Local Variables)](#global_and_local_variables)
|
||||
- [类型属性(Type Properties)](#type_properties)
|
||||
|
||||
**属性**将值跟特定的类、结构或枚举关联。存储属性存储常量或变量作为实例的一部分,计算属性计算(而不是存储)一个值。计算属性可以用于类、结构体和枚举里,存储属性只能用于类和结构体。
|
||||
*属性*将值跟特定的类、结构或枚举关联。存储属性存储常量或变量作为实例的一部分,而计算属性计算(不是存储)一个值。计算属性可以用于类、结构体和枚举,存储属性只能用于类和结构体。
|
||||
|
||||
存储属性和计算属性通常用于特定类型的实例,但是,属性也可以直接用于类型本身,这种属性称为类型属性。
|
||||
存储属性和计算属性通常与特定类型的实例关联。但是,属性也可以直接作用于类型本身,这种属性称为类型属性。
|
||||
|
||||
另外,还可以定义属性观察器来监控属性值的变化,以此来触发一个自定义的操作。属性观察器可以添加到自己写的存储属性上,也可以添加到从父类继承的属性上。
|
||||
另外,还可以定义属性观察器来监控属性值的变化,以此来触发一个自定义的操作。属性观察器可以添加到自己定义的存储属性上,也可以添加到从父类继承的属性上。
|
||||
|
||||
<a name="stored_properties"></a>
|
||||
## 存储属性
|
||||
|
||||
简单来说,一个存储属性就是存储在特定类或结构体的实例里的一个常量或变量,存储属性可以是*变量存储属性*(用关键字`var`定义),也可以是*常量存储属性*(用关键字`let`定义)。
|
||||
简单来说,一个存储属性就是存储在特定类或结构体的实例里的一个常量或变量。存储属性可以是*变量存储属性*(用关键字`var`定义),也可以是*常量存储属性*(用关键字`let`定义)。
|
||||
|
||||
可以在定义存储属性的时候指定默认值,请参考[构造过程](../chapter2/14_Initialization.html)一章的[默认属性值](../chapter2/14_Initialization.html#default_property_values)一节。也可以在构造过程中设置或修改存储属性的值,甚至修改常量存储属性的值,请参考[构造过程](../chapter2/14_Initialization.html)一章的[在初始化阶段修改常量存储属性](../chapter2/14_Initialization.html#modifying_constant_properties_during_initialization)一节。
|
||||
|
||||
@ -38,12 +38,12 @@ rangeOfThreeItems.firstValue = 6
|
||||
// 该区间现在表示整数6,7,8
|
||||
```
|
||||
|
||||
`FixedLengthRange`的实例包含一个名为`firstValue`的变量存储属性和一个名为`length`的常量存储属性。在上面的例子中,`length`在创建实例的时候被赋值,因为它是一个常量存储属性,所以之后无法修改它的值。
|
||||
`FixedLengthRange`的实例包含一个名为`firstValue`的变量存储属性和一个名为`length`的常量存储属性。在上面的例子中,`length`在创建实例的时候被初始化,因为它是一个常量存储属性,所以之后无法修改它的值。
|
||||
|
||||
<a name="stored_properties_of_constant_structure_instances"></a>
|
||||
### 常量和存储属性
|
||||
### 常量结构体的存储属性
|
||||
|
||||
如果创建了一个结构体的实例并赋值给一个常量,则无法修改实例的任何属性,即使定义了变量存储属性:
|
||||
如果创建了一个结构体的实例并将其赋值给一个常量,则无法修改该实例的任何属性,即使定义了变量存储属性:
|
||||
|
||||
```swift
|
||||
let rangeOfFourItems = FixedLengthRange(firstValue: 0, length: 4)
|
||||
@ -52,11 +52,11 @@ rangeOfFourItems.firstValue = 6
|
||||
// 尽管 firstValue 是个变量属性,这里还是会报错
|
||||
```
|
||||
|
||||
因为`rangeOfFourItems`声明成了常量(用`let`关键字),即使`firstValue`是一个变量属性,也无法再修改它了。
|
||||
因为`rangeOfFourItems`被声明成了常量(用`let`关键字),即使`firstValue`是一个变量属性,也无法再修改它了。
|
||||
|
||||
这种行为是由于结构体(struct)属于*值类型*。当值类型的实例被声明为常量的时候,它的所有属性也就成了常量。
|
||||
|
||||
属于*引用类型*的类(class)则不一样,把一个引用类型的实例赋给一个常量后,仍然可以修改实例的变量属性。
|
||||
属于*引用类型*的类(class)则不一样。把一个引用类型的实例赋给一个常量后,仍然可以修改该实例的变量属性。
|
||||
|
||||
<a name="lazy_stored_properties"></a>
|
||||
### 延迟存储属性
|
||||
@ -64,11 +64,11 @@ rangeOfFourItems.firstValue = 6
|
||||
延迟存储属性是指当第一次被调用的时候才会计算其初始值的属性。在属性声明前使用`lazy`来标示一个延迟存储属性。
|
||||
|
||||
> 注意:
|
||||
> 必须将延迟存储属性声明成变量(使用`var`关键字),因为属性的值在实例构造完成之前可能无法得到。而常量属性在构造过程完成之前必须要有初始值,因此无法声明成延迟属性。
|
||||
> 必须将延迟存储属性声明成变量(使用`var`关键字),因为属性的初始值可能在实例构造完成之后才会得到。而常量属性在构造过程完成之前必须要有初始值,因此无法声明成延迟属性。
|
||||
|
||||
延迟属性很有用,当属性的值依赖于在实例的构造过程结束前无法知道具体值的外部因素时,或者当属性的值需要复杂或大量计算时,可以只在需要的时候来计算它。
|
||||
延迟属性很有用,当属性的值依赖于在实例的构造过程结束后才会知道具体值的外部因素时,或者当获得属性的初始值需要复杂或大量计算时,可以只在需要的时候计算它。
|
||||
|
||||
下面的例子使用了延迟存储属性来避免复杂类的不必要的初始化。例子中定义了`DataImporter`和`DataManager`两个类,下面是部分代码:
|
||||
下面的例子使用了延迟存储属性来避免复杂类中不必要的初始化。例子中定义了`DataImporter`和`DataManager`两个类,下面是部分代码:
|
||||
|
||||
```swift
|
||||
class DataImporter {
|
||||
@ -94,30 +94,32 @@ manager.data.append("Some more data")
|
||||
|
||||
`DataManager`类包含一个名为`data`的存储属性,初始值是一个空的字符串(`String`)数组。虽然没有写出全部代码,`DataManager`类的目的是管理和提供对这个字符串数组的访问。
|
||||
|
||||
`DataManager`的一个功能是从文件导入数据,该功能由`DataImporter`类提供,`DataImporter`需要消耗不少时间完成初始化:因为它的实例在初始化时可能要打开文件,还要读取文件内容到内存。
|
||||
`DataManager`的一个功能是从文件导入数据。该功能由`DataImporter`类提供,`DataImporter`完成初始化需要消耗不少时间:因为它的实例在初始化时可能要打开文件,还要读取文件内容到内存。
|
||||
|
||||
`DataManager`也可能不从文件中导入数据。所以当`DataManager`的实例被创建时,没必要创建一个`DataImporter`的实例,更明智的是当用到`DataImporter`的时候才去创建它。
|
||||
`DataManager`也可能不从文件中导入数据就完成了管理数据的功能。所以当`DataManager`的实例被创建时,没必要创建一个`DataImporter`的实例,更明智的是当第一次用到`DataImporter`的时候才去创建它。
|
||||
|
||||
由于使用了`lazy`,`importer`属性只有在第一次被访问的时候才被创建。比如访问它的属性`fileName`时:
|
||||
|
||||
```swift
|
||||
println(manager.importer.fileName)
|
||||
print(manager.importer.fileName)
|
||||
// DataImporter 实例的 importer 属性现在被创建了
|
||||
// 输出 "data.txt”
|
||||
```
|
||||
|
||||
> 注意:
|
||||
> 如果一个被标记为`lazy`的属性在没有初始化时就同时被多个线程访问,则无法保证该属性只会被初始化一次。
|
||||
|
||||
<a name="stored_properties_and_instance_variables"></a>
|
||||
### 存储属性和实例变量
|
||||
|
||||
如果您有过 Objective-C 经验,应该知道 Objective-C 为类实例存储值和引用提供两种方法。对于属性来说,也可以使用实例变量作为属性值的后端存储。
|
||||
|
||||
Swift 编程语言中把这些理论统一用属性来实现。Swift 中的属性没有对应的实例变量,属性的后端存储也无法直接访问。这就避免了不同场景下访问方式的困扰,同时也将属性的定义简化成一个语句。
|
||||
一个类型中属性的全部信息——包括命名、类型和内存管理特征——都在唯一一个地方(类型定义中)定义。
|
||||
Swift 编程语言中把这些理论统一用属性来实现。Swift 中的属性没有对应的实例变量,属性的后端存储也无法直接访问。这就避免了不同场景下访问方式的困扰,同时也将属性的定义简化成一个语句。一个类型中属性的全部信息——包括命名、类型和内存管理特征——都在唯一一个地方(类型定义中)定义。
|
||||
|
||||
<a name="computed_properties"></a>
|
||||
## 计算属性
|
||||
|
||||
除存储属性外,类、结构体和枚举可以定义*计算属性*,计算属性不直接存储值,而是提供一个 getter 来获取值,一个可选的 setter 来间接设置其他属性或变量的值。
|
||||
除存储属性外,类、结构体和枚举可以定义*计算属性*。计算属性不直接存储值,而是提供一个 getter 和一个可选的 setter,来间接获取和设置其他属性或变量的值。
|
||||
|
||||
```swift
|
||||
struct Point {
|
||||
@ -145,23 +147,23 @@ var square = Rect(origin: Point(x: 0.0, y: 0.0),
|
||||
size: Size(width: 10.0, height: 10.0))
|
||||
let initialSquareCenter = square.center
|
||||
square.center = Point(x: 15.0, y: 15.0)
|
||||
println("square.origin is now at (\(square.origin.x), \(square.origin.y))")
|
||||
print("square.origin is now at (\(square.origin.x), \(square.origin.y))")
|
||||
// 输出 "square.origin is now at (10.0, 10.0)”
|
||||
```
|
||||
|
||||
这个例子定义了 3 个几何形状的结构体:
|
||||
这个例子定义了 3 个结构体来描述几何形状:
|
||||
|
||||
- `Point`封装了一个`(x, y)`的坐标
|
||||
- `Size`封装了一个`width`和`height`
|
||||
- `Size`封装了一个`width`和一个`height`
|
||||
- `Rect`表示一个有原点和尺寸的矩形
|
||||
|
||||
`Rect`也提供了一个名为`center`的计算属性。一个矩形的中心点可以从原点和尺寸来算出,所以不需要将它以显式声明的`Point`来保存。`Rect`的计算属性`center`提供了自定义的 getter 和 setter 来获取和设置矩形的中心点,就像它有一个存储属性一样。
|
||||
`Rect`也提供了一个名为`center`的计算属性。一个矩形的中心点可以从原点(`origin`)和尺寸(`size`)算出,所以不需要将它以显式声明的`Point`来保存。`Rect`的计算属性`center`提供了自定义的 getter 和 setter 来获取和设置矩形的中心点,就像它有一个存储属性一样。
|
||||
|
||||
例子中接下来创建了一个名为`square`的`Rect`实例,初始值原点是`(0, 0)`,宽度高度都是`10`。如图所示蓝色正方形。
|
||||
上述例子中创建了一个名为`square`的`Rect`实例,初始值原点是`(0, 0)`,宽度高度都是`10`。如下图中蓝色正方形所示。
|
||||
|
||||
`square`的`center`属性可以通过点运算符(`square.center`)来访问,这会调用 getter 来获取属性的值。跟直接返回已经存在的值不同,getter 实际上通过计算然后返回一个新的`Point`来表示`square`的中心点。如代码所示,它正确返回了中心点`(5, 5)`。
|
||||
`square`的`center`属性可以通过点运算符(`square.center`)来访问,这会调用该属性的 getter 来获取它的值。跟直接返回已经存在的值不同,getter 实际上通过计算然后返回一个新的`Point`来表示`square`的中心点。如代码所示,它正确返回了中心点`(5, 5)`。
|
||||
|
||||
`center`属性之后被设置了一个新的值`(15, 15)`,表示向右上方移动正方形到如图所示橙色正方形的位置。设置属性`center`的值会调用 setter 来修改属性`origin`的`x`和`y`的值,从而实现移动正方形到新的位置。
|
||||
`center`属性之后被设置了一个新的值`(15, 15)`,表示向右上方移动正方形到如下图橙色正方形所示的位置。设置属性`center`的值会调用它的 setter 来修改属性`origin`的`x`和`y`的值,从而实现移动正方形到新的位置。
|
||||
|
||||
<img src="https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Art/computedProperties_2x.png" alt="Computed Properties sample" width="388" height="387" />
|
||||
|
||||
@ -194,10 +196,8 @@ struct AlternativeRect {
|
||||
只有 getter 没有 setter 的计算属性就是*只读计算属性*。只读计算属性总是返回一个值,可以通过点运算符访问,但不能设置新的值。
|
||||
|
||||
> 注意:
|
||||
>
|
||||
> 必须使用`var`关键字定义计算属性,包括只读计算属性,因为它们的值不是固定的。`let`关键字只用来声明常量属性,表示初始化后再也无法修改的值。
|
||||
|
||||
|
||||
只读计算属性的声明可以去掉`get`关键字和花括号:
|
||||
|
||||
```swift
|
||||
@ -208,11 +208,11 @@ struct Cuboid {
|
||||
}
|
||||
}
|
||||
let fourByFiveByTwo = Cuboid(width: 4.0, height: 5.0, depth: 2.0)
|
||||
println("the volume of fourByFiveByTwo is \(fourByFiveByTwo.volume)")
|
||||
print("the volume of fourByFiveByTwo is \(fourByFiveByTwo.volume)")
|
||||
// 输出 "the volume of fourByFiveByTwo is 40.0"
|
||||
```
|
||||
|
||||
这个例子定义了一个名为`Cuboid`的结构体,表示三维空间的立方体,包含`width`、`height`和`depth`属性,还有一个名为`volume`的只读计算属性用来返回立方体的体积。设置`volume`的值毫无意义,因为通过`width`、`height`和`depth`就能算出`volume`。然而,`Cuboid`提供一个只读计算属性来让外部用户直接获取体积是很有用的。
|
||||
这个例子定义了一个名为`Cuboid`的结构体,表示三维空间的立方体,包含`width`、`height`和`depth`属性。结构体还有一个名为`volume`的只读计算属性用来返回立方体的体积。设置`volume`的值毫无意义,因为无法确定修改`width`、`height`和`depth`三者中的哪些值来匹配新的`volume`,从而造成歧义。然而,`Cuboid`提供一个只读计算属性来让外部用户直接获取体积是很有用的。
|
||||
|
||||
<a name="property_observers"></a>
|
||||
## 属性观察器
|
||||
@ -222,32 +222,32 @@ println("the volume of fourByFiveByTwo is \(fourByFiveByTwo.volume)")
|
||||
可以为除了延迟存储属性之外的其他存储属性添加属性观察器,也可以通过重载属性的方式为继承的属性(包括存储属性和计算属性)添加属性观察器。属性重载请参考[继承](chapter/13_Inheritance.html)一章的[重载](chapter/13_Inheritance.html#overriding)。
|
||||
|
||||
> 注意:
|
||||
> 不需要为无法重载的计算属性添加属性观察器,因为可以通过 setter 直接监控和响应值的变化。
|
||||
> 不需要为非重载的计算属性添加属性观察器,因为可以通过它的 setter 直接监控和响应值的变化。
|
||||
|
||||
可以为属性添加如下的一个或全部观察器:
|
||||
|
||||
- `willSet`在设置新的值之前调用
|
||||
- `willSet`在新的值被设置之前调用
|
||||
- `didSet`在新的值被设置之后立即调用
|
||||
|
||||
`willSet`观察器会将新的属性值作为固定参数传入,在`willSet`的实现代码中可以为这个参数指定一个名称,如果不指定则参数仍然可用,这时使用默认名称`newValue`表示。
|
||||
`willSet`观察器会将新的属性值作为常量参数传入,在`willSet`的实现代码中可以为这个参数指定一个名称,如果不指定则参数仍然可用,这时使用默认名称`newValue`表示。
|
||||
|
||||
类似地,`didSet`观察器会将旧的属性值作为参数传入,可以为该参数命名或者使用默认参数名`oldValue`。
|
||||
|
||||
> 注意:
|
||||
>
|
||||
> `willSet`和`didSet`观察器在属性初始化过程中不会被调用,它们只会当属性的值在初始化之外的地方被设置时被调用。
|
||||
> 父类的属性在子类的构造器中被赋值时,它在父类中的`willSet`和`didSet`观察器会被调用。
|
||||
> 有关构造器代理的更多信息,请参考[值类型的构造器代理](chapter/14_Initialization.html#initializer_delegation_for_value_types)和[构造器链](chapter/14_Initialization.html#initialization_chain)。
|
||||
|
||||
这里是一个`willSet`和`didSet`的实际例子,其中定义了一个名为`StepCounter`的类,用来统计当人步行时的总步数,可以跟计步器或其他日常锻炼的统计装置的输入数据配合使用。
|
||||
这里是一个`willSet`和`didSet`的实际例子,其中定义了一个名为`StepCounter`的类,用来统计当人步行时的总步数。这个类可以跟计步器或其他日常锻炼的统计装置的输入数据配合使用。
|
||||
|
||||
```swift
|
||||
class StepCounter {
|
||||
var totalSteps: Int = 0 {
|
||||
willSet(newTotalSteps) {
|
||||
println("About to set totalSteps to \(newTotalSteps)")
|
||||
print("About to set totalSteps to \(newTotalSteps)")
|
||||
}
|
||||
didSet {
|
||||
if totalSteps > oldValue {
|
||||
println("Added \(totalSteps - oldValue) steps")
|
||||
print("Added \(totalSteps - oldValue) steps")
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -270,19 +270,19 @@ stepCounter.totalSteps = 896
|
||||
|
||||
例子中的`willSet`观察器将表示新值的参数自定义为`newTotalSteps`,这个观察器只是简单的将新的值输出。
|
||||
|
||||
`didSet`观察器在`totalSteps`的值改变后被调用,它把新的值和旧的值进行对比,如果总的步数增加了,就输出一个消息表示增加了多少步。`didSet`没有提供自定义名称,所以默认值`oldValue`表示旧值的参数名。
|
||||
`didSet`观察器在`totalSteps`的值改变后被调用,它把新的值和旧的值进行对比,如果总的步数增加了,就输出一个消息表示增加了多少步。`didSet`没有为旧的值提供自定义名称,所以默认值`oldValue`表示旧值的参数名。
|
||||
|
||||
> 注意:
|
||||
> 如果在`didSet`观察器里为属性赋值,这个值会替换观察器之前设置的值。
|
||||
> 如果在一个属性的`didSet`观察器里为它赋值,这个值会替换该观察器之前设置的值。
|
||||
|
||||
<a name="global_and_local_variables"></a>
|
||||
##全局变量和局部变量
|
||||
|
||||
计算属性和属性观察器所描述的模式也可以用于*全局变量*和*局部变量*,全局变量是在函数、方法、闭包或任何类型之外定义的变量,局部变量是在函数、方法或闭包内部定义的变量。
|
||||
计算属性和属性观察器所描述的模式也可以用于*全局变量*和*局部变量*。全局变量是在函数、方法、闭包或任何类型之外定义的变量。局部变量是在函数、方法或闭包内部定义的变量。
|
||||
|
||||
前面章节提到的全局或局部变量都属于存储型变量,跟存储属性类似,它提供特定类型的存储空间,并允许读取和写入。
|
||||
|
||||
另外,在全局或局部范围都可以定义计算型变量和为存储型变量定义观察器,计算型变量跟计算属性一样,返回一个计算的值而不是存储值,声明格式也完全一样。
|
||||
另外,在全局或局部范围都可以定义计算型变量和为存储型变量定义观察器。计算型变量跟计算属性一样,返回一个计算的值而不是存储值,声明格式也完全一样。
|
||||
|
||||
> 注意:
|
||||
> 全局的常量或变量都是延迟计算的,跟[延迟存储属性](#lazy_stored_properties)相似,不同的地方在于,全局的常量或变量不需要标记`lazy`特性。
|
||||
@ -297,9 +297,7 @@ stepCounter.totalSteps = 896
|
||||
|
||||
类型属性用于定义特定类型所有实例共享的数据,比如所有实例都能用的一个常量(就像 C 语言中的静态常量),或者所有实例都能访问的一个变量(就像 C 语言中的静态变量)。
|
||||
|
||||
对于值类型(指结构体和枚举)可以定义存储型和计算型类型属性,对于类(class)则只能定义计算型类型属性。
|
||||
|
||||
值类型的存储型类型属性可以是变量或常量,计算型类型属性跟实例的计算属性一样定义成变量属性。
|
||||
值类型的存储型类型属性可以是变量或常量,计算型类型属性跟实例的计算属性一样只能定义成变量属性。
|
||||
|
||||
> 注意:
|
||||
> 跟实例的存储属性不同,必须给存储型类型属性指定默认值,因为类型本身无法在初始化过程中使用构造器给类型属性赋值。
|
||||
@ -307,26 +305,30 @@ stepCounter.totalSteps = 896
|
||||
<a name="type_property_syntax"></a>
|
||||
###类型属性语法
|
||||
|
||||
在 C 或 Objective-C 中,静态常量和静态变量的定义是通过特定类型加上`global`关键字。在 Swift 编程语言中,类型属性是作为类型定义的一部分写在类型最外层的花括号内,因此它的作用范围也就在类型支持的范围内。
|
||||
在 C 或 Objective-C 中,与某个类型关联的静态常量和静态变量,是作为全局(*global*)静态变量定义的。但是在 Swift 编程语言中,类型属性是作为类型定义的一部分写在类型最外层的花括号内,因此它的作用范围也就在类型支持的范围内。
|
||||
|
||||
使用关键字`static`来定义值类型的类型属性,关键字`class`来为类(class)定义类型属性。下面的例子演示了存储型和计算型类型属性的语法:
|
||||
使用关键字`static`来定义类型属性。在为类(class)定义计算型类型属性时,可以使用关键字`class`来支持子类对父类的实现进行重写。下面的例子演示了存储型和计算型类型属性的语法:
|
||||
|
||||
```swift
|
||||
struct SomeStructure {
|
||||
static var storedTypeProperty = "Some value."
|
||||
static var computedTypeProperty: Int {
|
||||
// 这里返回一个 Int 值
|
||||
return 1
|
||||
}
|
||||
}
|
||||
enum SomeEnumeration {
|
||||
static var storedTypeProperty = "Some value."
|
||||
static var computedTypeProperty: Int {
|
||||
// 这里返回一个 Int 值
|
||||
return 6
|
||||
}
|
||||
}
|
||||
class SomeClass {
|
||||
class var computedTypeProperty: Int {
|
||||
// 这里返回一个 Int 值
|
||||
static var storedTypeProperty = "Some value."
|
||||
static var computedTypeProperty: Int {
|
||||
return 27
|
||||
}
|
||||
class var overrideableComputedTypeProperty: Int {
|
||||
return 107
|
||||
}
|
||||
}
|
||||
```
|
||||
@ -337,17 +339,18 @@ class SomeClass {
|
||||
<a name="querying_and_setting_type_properties"></a>
|
||||
###获取和设置类型属性的值
|
||||
|
||||
跟实例的属性一样,类型属性的访问也是通过点运算符来进行,但是,类型属性是通过类型本身来获取和设置,而不是通过实例。比如:
|
||||
跟实例的属性一样,类型属性的访问也是通过点运算符来进行。但是,类型属性是通过类型本身来获取和设置,而不是通过实例。比如:
|
||||
|
||||
```swift
|
||||
println(SomeClass.computedTypeProperty)
|
||||
// 输出 "42"
|
||||
|
||||
println(SomeStructure.storedTypeProperty)
|
||||
print(SomeStructure.storedTypeProperty)
|
||||
// 输出 "Some value."
|
||||
SomeStructure.storedTypeProperty = "Another value."
|
||||
println(SomeStructure.storedTypeProperty)
|
||||
print(SomeStructure.storedTypeProperty)
|
||||
// 输出 "Another value.”
|
||||
print(SomeEnumeration.computedTypeProperty)
|
||||
// 输出 "6"
|
||||
print(SomeClass.computedTypeProperty)
|
||||
// 输出 "27"
|
||||
```
|
||||
|
||||
下面的例子定义了一个结构体,使用两个存储型类型属性来表示多个声道的声音电平值,每个声道有一个 0 到 10 之间的整数表示声音电平值。
|
||||
@ -356,7 +359,7 @@ println(SomeStructure.storedTypeProperty)
|
||||
|
||||
<img src="https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Art/staticPropertiesVUMeter_2x.png" alt="Static Properties VUMeter" width="243" height="357" />
|
||||
|
||||
上面所描述的声道模型使用`AudioChannel`结构体来表示:
|
||||
上面所描述的声道模型使用`AudioChannel`结构体的实例来表示:
|
||||
|
||||
```swift
|
||||
struct AudioChannel {
|
||||
@ -383,10 +386,10 @@ struct AudioChannel {
|
||||
|
||||
`AudioChannel`也定义了一个名为`currentLevel`的实例存储属性,表示当前声道现在的电平值,取值为 0 到 10。
|
||||
|
||||
属性`currentLevel`包含`didSet`属性观察器来检查每次新设置后的属性值,有如下两个检查:
|
||||
属性`currentLevel`包含`didSet`属性观察器来检查每次新设置后的属性值,它有如下两个检查:
|
||||
|
||||
- 如果`currentLevel`的新值大于允许的阈值`thresholdLevel`,属性观察器将`currentLevel`的值限定为阈值`thresholdLevel`。
|
||||
- 如果修正后的`currentLevel`值大于任何之前任意`AudioChannel`实例中的值,属性观察器将新值保存在静态属性`maxInputLevelForAllChannels`中。
|
||||
- 如果前一个修正后的`currentLevel`值大于任何之前任意`AudioChannel`实例中的值,属性观察器将新值保存在静态类型属性`maxInputLevelForAllChannels`中。
|
||||
|
||||
> 注意:
|
||||
> 在第一个检查过程中,`didSet`属性观察器将`currentLevel`设置成了不同的值,但这时不会再次调用属性观察器。
|
||||
@ -402,9 +405,9 @@ var rightChannel = AudioChannel()
|
||||
|
||||
```swift
|
||||
leftChannel.currentLevel = 7
|
||||
println(leftChannel.currentLevel)
|
||||
print(leftChannel.currentLevel)
|
||||
// 输出 "7"
|
||||
println(AudioChannel.maxInputLevelForAllChannels)
|
||||
print(AudioChannel.maxInputLevelForAllChannels)
|
||||
// 输出 "7"
|
||||
```
|
||||
|
||||
@ -412,8 +415,8 @@ println(AudioChannel.maxInputLevelForAllChannels)
|
||||
|
||||
```swift
|
||||
rightChannel.currentLevel = 11
|
||||
println(rightChannel.currentLevel)
|
||||
print(rightChannel.currentLevel)
|
||||
// 输出 "10"
|
||||
println(AudioChannel.maxInputLevelForAllChannels)
|
||||
print(AudioChannel.maxInputLevelForAllChannels)
|
||||
// 输出 "10"
|
||||
```
|
||||
|
||||
@ -11,9 +11,9 @@
|
||||
- [下标脚本用法](#subscript_usage)
|
||||
- [下标脚本选项](#subscript_options)
|
||||
|
||||
*下标脚本* 可以定义在类(Class)、结构体(structure)和枚举(enumeration)这些目标中,可以认为是访问对象、集合或序列的快捷方式,不需要再调用实例的特定的赋值和访问方法。举例来说,用下标脚本访问一个数组(Array)实例中的元素可以这样写 `someArray[index]` ,访问字典(Dictionary)实例中的元素可以这样写 `someDictionary[key]`。
|
||||
*下标脚本* 可以定义在类(Class)、结构体(structure)和枚举(enumeration)这些目标中,可以认为是访问集合(collection),列表(list)或序列(sequence的快捷方式,使用下标脚本的索引设置和获取值,不需要再调用实例的特定的赋值和访问方法。举例来说,用下标脚本访问一个数组(Array)实例中的元素可以这样写 `someArray[index]` ,访问字典(Dictionary)实例中的元素可以这样写 `someDictionary[key]`。
|
||||
|
||||
对于同一个目标可以定义多个下标脚本,通过索引值类型的不同来进行重载,而且索引值的个数可以是多个。
|
||||
对于同一个目标可以定义多个下标脚本,通过索引值类型的不同来进行重载,下标脚本不限于单个纬度,你可以定义多个入参的下标脚本满足自定义类型的需求。
|
||||
|
||||
> 译者:这里附属脚本重载在本小节中原文并没有任何演示
|
||||
|
||||
@ -63,7 +63,7 @@ println("3的6倍是\(threeTimesTable[6])")
|
||||
你可以通过下标脚本来得到结果,比如`threeTimesTable[6]`。这条语句访问了`threeTimesTable`的第六个元素,返回`6`的`3`倍即`18`。
|
||||
|
||||
>注意:
|
||||
> `TimesTable`例子是基于一个固定的数学公式。它并不适合开放写权限来对`threeTimesTable[someIndex]`进行赋值操作,这也是为什么附属脚本只定义为只读的原因。
|
||||
> `TimesTable`例子是基于一个固定的数学公式。它并不适合对`threeTimesTable[someIndex]`进行赋值操作,这也是为什么附属脚本只定义为只读的原因。
|
||||
|
||||
<a name="subscript_usage"></a>
|
||||
## 下标脚本用法
|
||||
@ -77,7 +77,7 @@ var numberOfLegs = ["spider": 8, "ant": 6, "cat": 4]
|
||||
numberOfLegs["bird"] = 2
|
||||
```
|
||||
|
||||
上例定义一个名为`numberOfLegs`的变量并用一个字典字面量初始化出了包含三对键值的字典实例。`numberOfLegs`的字典存放值类型推断为`Dictionary<String, Int>`。字典实例创建完成之后通过下标脚本的方式将整型值`2`赋值到字典实例的索引为`bird`的位置中。
|
||||
上例定义一个名为`numberOfLegs`的变量并用一个字典字面量初始化出了包含三对键值的字典实例。`numberOfLegs`的字典存放值类型推断为`[String:Int]`。字典实例创建完成之后通过下标脚本的方式将整型值`2`赋值到字典实例的索引为`bird`的位置中。
|
||||
|
||||
更多关于字典(Dictionary)下标脚本的信息请参考[读取和修改字典](../chapter2/04_Collection_Types.html)
|
||||
|
||||
@ -118,7 +118,7 @@ struct Matrix {
|
||||
}
|
||||
```
|
||||
|
||||
`Matrix`提供了一个两个入参的构造方法,入参分别是`rows`和`columns`,创建了一个足够容纳`rows * columns`个数的`Double`类型数组。为了存储,将数组的大小和数组每个元素初始值0.0,都传入数组的构造方法中来创建一个正确大小的新数组。关于数组的构造方法和析构方法请参考[创建并且构造一个数组](../chapter2/04_Collection_Types.html)。
|
||||
`Matrix`提供了一个两个入参的构造方法,入参分别是`rows`和`columns`,创建了一个足够容纳`rows * columns`个数的`Double`类型数组。通过传入数组长度和初始值0.0到数组的一个构造器,将`Matrix`中每个元素初始值0.0。关于数组的构造方法和析构方法请参考[创建并且构造一个数组](../chapter2/04_Collection_Types.html)。
|
||||
|
||||
你可以通过传入合适的`row`和`column`的数量来构造一个新的`Matrix`实例:
|
||||
|
||||
@ -151,7 +151,7 @@ matrix[1, 0] = 3.2
|
||||
3.2, 0.0]
|
||||
```
|
||||
|
||||
`Matrix`下标脚本的`getter`和`setter`中同时调用了下标脚本入参的`row`和`column`是否有效的判断。为了方便进行断言,`Matrix`包含了一个名为`indexIsValid`的成员方法,用来确认入参的`row`或`column`值是否会造成数组越界:
|
||||
`Matrix`下标脚本的`getter`和`setter`中同时调用了下标脚本入参的`row`和`column`是否有效的判断。为了方便进行断言,`Matrix`包含了一个名为`indexIsValidForRow(_:column:)`的成员方法,用来确认入参的`row`或`column`值是否会造成数组越界:
|
||||
|
||||
```swift
|
||||
func indexIsValidForRow(row: Int, column: Int) -> Bool {
|
||||
|
||||
@ -11,11 +11,11 @@
|
||||
- [重写(Overriding)](#overriding)
|
||||
- [防止重写](#preventing_overrides)
|
||||
|
||||
一个类可以*继承(inherit)*另一个类的方法(methods),属性(property)和其它特性。当一个类继承其它类时,继承类叫*子类(subclass)*,被继承类叫*超类(或父类,superclass)*。在 Swift 中,继承是区分「类」与其它类型的一个基本特征。
|
||||
一个类可以*继承(inherit)*另一个类的方法(methods),属性(properties)和其它特性。当一个类继承其它类时,继承类叫*子类(subclass)*,被继承类叫*超类(或父类,superclass)*。在 Swift 中,继承是区分「类」与其它类型的一个基本特征。
|
||||
|
||||
在 Swift 中,类可以调用和访问超类的方法,属性和下标脚本(subscripts),并且可以重写(override)这些方法,属性和下标脚本来优化或修改它们的行为。Swift 会检查你的重写定义在超类中是否有匹配的定义,以此确保你的重写行为是正确的。
|
||||
|
||||
可以为类中继承来的属性添加属性观察器(property observer),这样一来,当属性值改变时,类就会被通知到。可以为任何属性添加属性观察器,无论它原本被定义为存储型属性(stored property)还是计算型属性(computed property)。
|
||||
可以为类中继承来的属性添加属性观察器(property observers),这样一来,当属性值改变时,类就会被通知到。可以为任何属性添加属性观察器,无论它原本被定义为存储型属性(stored property)还是计算型属性(computed property)。
|
||||
|
||||
<a name="defining_a_base_class"></a>
|
||||
## 定义一个基类(Base class)
|
||||
@ -27,7 +27,7 @@ Swift 中的类并不是从一个通用的基类继承而来。如果你不为
|
||||
|
||||
下面的例子定义了一个叫`Vehicle`的基类。这个基类声明了一个名为`currentSpeed `,默认值是0.0的存储属性(属性类型推断为`Double `)。`currentSpeed `属性的值被一个`String` 类型的只读计算型属性`description`使用,用来创建车辆的描述。
|
||||
|
||||
`Vehicle`基类也定义了一个名为`makeNoise`的方法。这个方法实际上不为`Vehicle`实例做任何事,但之后将会被`Vehicle`的子类定制
|
||||
`Vehicle`基类也定义了一个名为`makeNoise`的方法。这个方法实际上不为`Vehicle`实例做任何事,但之后将会被`Vehicle`的子类定制:
|
||||
|
||||
```swift
|
||||
class Vehicle {
|
||||
@ -41,7 +41,7 @@ class Vehicle {
|
||||
}
|
||||
```
|
||||
|
||||
您可以用初始化语法创建一个`Vehicle `的新实例,即 `TypeName`后面跟一个空括号:
|
||||
您可以用初始化语法创建一个`Vehicle `的新实例,即类名后面跟一个空括号:
|
||||
```swift
|
||||
let someVehicle = Vehicle()
|
||||
```
|
||||
@ -53,6 +53,8 @@ println("Vehicle: \(someVehicle.description)")
|
||||
// Vehicle: traveling at 0.0 miles per hour
|
||||
```
|
||||
|
||||
`Vehicle`类定义了一个通用特性的车辆类,实际上没什么用处。为了让它变得更加有用,需要改进它能够描述一个更加具体的车辆类。
|
||||
|
||||
<a name="subclassing"></a>
|
||||
## 子类生成(Subclassing)
|
||||
|
||||
@ -66,11 +68,7 @@ class SomeClass: SomeSuperclass {
|
||||
}
|
||||
```
|
||||
|
||||
下一个例子,定义一个更具体的车辆类叫`Bicycle`。这个新类是在 `Vehicle`类的基础上创建起来。因此你需要将`Vehicle`类放在 `Bicycle`类后面,用冒号分隔。
|
||||
|
||||
我们可以将这读作:
|
||||
|
||||
“定义一个新的类叫`Bicycle `,它继承了`Vehicle`的特性”;
|
||||
下一个例子,定义一个叫`Bicycle`的子类,继承成父类`Vehicle`
|
||||
|
||||
```swift
|
||||
class Bicycle: Vehicle {
|
||||
@ -161,7 +159,7 @@ train.makeNoise()
|
||||
|
||||
### 重写属性
|
||||
|
||||
你可以重写继承来的实例属性或类属性,提供自己定制的getter和setter,或添加属性观察器使重写的属性观察属性值什么时候发生改变。
|
||||
你可以重写继承来的实例属性或类属性,提供自己定制的getter和setter,或添加属性观察器使重写的属性可以观察属性值什么时候发生改变。
|
||||
|
||||
#### 重写属性的Getters和Setters
|
||||
|
||||
@ -228,7 +226,7 @@ println("AutomaticCar: \(automatic.description)")
|
||||
|
||||
你可以通过把方法,属性或下标脚本标记为*`final`*来防止它们被重写,只需要在声明关键字前加上`final`特性即可。(例如:`final var`, `final func`, `final class func`, 以及 `final subscript`)
|
||||
|
||||
如果你重写了`final`方法,属性或下标脚本,在编译时会报错。在扩展中,你添加到类里的方法,属性或下标脚本也可以在扩展的定义里标记为 final。
|
||||
如果你重写了`final`方法,属性或下标脚本,在编译时会报错。在类扩展中的方法,属性或下标脚本也可以在扩展的定义里标记为 final。
|
||||
|
||||
你可以通过在关键字`class`前添加`final`特性(`final class`)来将整个类标记为 final 的,这样的类是不可被继承的,否则会报编译错误。
|
||||
你可以通过在关键字`class`前添加`final`特性(`final class`)来将整个类标记为 final 的,这样的类是不可被继承的,任何子类试图继承此类时,在编译时会报错。
|
||||
|
||||
|
||||
@ -13,7 +13,7 @@
|
||||
- [闭包引起的循环强引用](#strong_reference_cycles_for_closures)
|
||||
- [解决闭包引起的循环强引用](#resolving_strong_reference_cycles_for_closures)
|
||||
|
||||
Swift 使用自动引用计数(ARC)这一机制来跟踪和管理你的应用程序的内存。通常情况下,Swift 的内存管理机制会一直起着作用,你无须自己来考虑内存的管理。ARC 会在类的实例不再被使用时,自动释放其占用的内存。
|
||||
Swift 使用自动引用计数(ARC)机制来跟踪和管理你的应用程序的内存。通常情况下,Swift 的内存管理机制会一直起着作用,你无须自己来考虑内存的管理。ARC 会在类的实例不再被使用时,自动释放其占用的内存。
|
||||
|
||||
然而,在少数情况下,ARC 为了能帮助你管理内存,需要更多的关于你的代码之间关系的信息。本章描述了这些情况,并且为你示范怎样启用 ARC 来管理你的应用程序的内存。
|
||||
|
||||
@ -23,13 +23,15 @@ Swift 使用自动引用计数(ARC)这一机制来跟踪和管理你的应
|
||||
<a name="how_arc_works"></a>
|
||||
## 自动引用计数的工作机制
|
||||
|
||||
当你每次创建一个类的新的实例的时候,ARC 会分配一大块内存用来储存实例的信息。内存中会包含实例的类型信息,以及这个实例所有相关属性的值。此外,当实例不再被使用时,ARC 释放实例所占用的内存,并让释放的内存能挪作他用。这确保了不再被使用的实例,不会一直占用内存空间。
|
||||
当你每次创建一个类的新的实例的时候,ARC 会分配一大块内存用来储存实例的信息。内存中会包含实例的类型信息,以及这个实例所有相关属性的值。
|
||||
|
||||
此外,当实例不再被使用时,ARC 释放实例所占用的内存,并让释放的内存能挪作他用。这确保了不再被使用的实例,不会一直占用内存空间。
|
||||
|
||||
然而,当 ARC 收回和释放了正在被使用中的实例,该实例的属性和方法将不能再被访问和调用。实际上,如果你试图访问这个实例,你的应用程序很可能会崩溃。
|
||||
|
||||
为了确保使用中的实例不会被销毁,ARC 会跟踪和计算每一个实例正在被多少属性,常量和变量所引用。哪怕实例的引用数为一,ARC都不会销毁这个实例。
|
||||
为了确保使用中的实例不会被销毁,ARC 会跟踪和计算每一个实例正在被多少属性,常量和变量所引用。哪怕实例的引用数为1,ARC都不会销毁这个实例。
|
||||
|
||||
为了使之成为可能,无论你将实例赋值给属性,常量或者是变量,属性,常量或者变量,都会对此实例创建强引用。之所以称之为强引用,是因为它会将实例牢牢的保持住,只要强引用还在,实例是不允许被销毁的。
|
||||
为了使上述成为可能,无论你将实例赋值给属性、常量或变量,它们都会创建此实例的强引用。之所以称之为“强”引用,是因为它会将实例牢牢的保持住,只要强引用还在,实例是不允许被销毁的。
|
||||
|
||||
<a name="arc_in_action"></a>
|
||||
## 自动引用计数实践
|
||||
@ -41,17 +43,17 @@ class Person {
|
||||
let name: String
|
||||
init(name: String) {
|
||||
self.name = name
|
||||
println("\(name) is being initialized")
|
||||
print("\(name) is being initialized")
|
||||
}
|
||||
deinit {
|
||||
println("\(name) is being deinitialized")
|
||||
print("\(name) is being deinitialized")
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
`Person`类有一个构造函数,此构造函数为实例的`name`属性赋值并打印出信息,以表明初始化过程生效。`Person`类同时也拥有析构函数,同样会在实例被销毁的时候打印出信息。
|
||||
`Person`类有一个构造函数,此构造函数为实例的`name`属性赋值,并打印一条消息以表明初始化过程生效。`Person`类也拥有一个析构函数,这个析构函数会在实例被销毁时打印一条消息。
|
||||
|
||||
接下来的代码片段定义了三个类型为`Person?`的变量,用来按照代码片段中的顺序,为新的`Person`实例建立多个引用。由于这些变量是被定义为可选类型(Person?,而不是Person),它们的值会被自动初始化为`nil`,目前还不会引用到`Person`类的实例。
|
||||
接下来的代码片段定义了三个类型为`Person?`的变量,用来按照代码片段中的顺序,为新的`Person`实例建立多个引用。由于这些变量是被定义为可选类型(`Person?`,而不是`Person`),它们的值会被自动初始化为`nil`,目前还不会引用到`Person`类的实例。
|
||||
|
||||
```swift
|
||||
var reference1: Person?
|
||||
@ -59,7 +61,7 @@ var reference2: Person?
|
||||
var reference3: Person?
|
||||
```
|
||||
|
||||
现在你可以创建`Person`类的新实例,并且将它赋值给三个变量其中的一个:
|
||||
现在你可以创建`Person`类的新实例,并且将它赋值给三个变量中的一个:
|
||||
|
||||
```swift
|
||||
reference1 = Person(name: "John Appleseed")
|
||||
@ -68,25 +70,25 @@ reference1 = Person(name: "John Appleseed")
|
||||
|
||||
应当注意到当你调用`Person`类的构造函数的时候,"John Appleseed is being initialized”会被打印出来。由此可以确定构造函数被执行。
|
||||
|
||||
由于`Person`类的新实例被赋值给了`reference1`变量,所以`reference1`到`Person`类的新实例之间建立了一个强引用。正是因为这个强引用,ARC 会保证`Person`实例被保持在内存中不被销毁。
|
||||
由于`Person`类的新实例被赋值给了`reference1`变量,所以`reference1`到`Person`类的新实例之间建立了一个强引用。正是因为这一个强引用,ARC 会保证`Person`实例被保持在内存中不被销毁。
|
||||
|
||||
如果你将同样的`Person`实例也赋值给其他两个变量,该实例又会多出两个强引用:
|
||||
如果你将同一个`Person`实例也赋值给其他两个变量,该实例又会多出两个强引用:
|
||||
|
||||
```swift
|
||||
reference2 = reference1
|
||||
reference3 = reference1
|
||||
```
|
||||
|
||||
现在这个`Person`实例已经有三个强引用了。
|
||||
现在这一个`Person`实例已经有三个强引用了。
|
||||
|
||||
如果你通过给两个变量赋值`nil`的方式断开两个强引用()包括最先的那个强引用),只留下一个强引用,`Person`实例不会被销毁:
|
||||
如果你通过给其中两个变量赋值`nil`的方式断开两个强引用(包括最先的那个强引用),只留下一个强引用,`Person`实例不会被销毁:
|
||||
|
||||
```swift
|
||||
reference1 = nil
|
||||
reference2 = nil
|
||||
```
|
||||
|
||||
ARC 会在第三个,也即最后一个强引用被断开的时候,销毁`Person`实例,这也意味着你不再使用这个`Person`实例:
|
||||
在你清楚地表明不再使用这个`Person`实例时,即第三个也就是最后一个强引用被断开时,ARC 会销毁它。
|
||||
|
||||
```swift
|
||||
reference3 = nil
|
||||
@ -98,9 +100,9 @@ reference3 = nil
|
||||
|
||||
在上面的例子中,ARC 会跟踪你所新创建的`Person`实例的引用数量,并且会在`Person`实例不再被需要时销毁它。
|
||||
|
||||
然而,我们可能会写出这样的代码,一个类永远不会有0个强引用。这种情况发生在两个类实例互相保持对方的强引用,并让对方不被销毁。这就是所谓的循环强引用。
|
||||
然而,我们可能会写出一个类实例的强引用数永远不能变成0的代码。如果两个类实例互相持有对方的强引用,因而每个实例都让对方一直存在,就是这种情况。这就是所谓的循环强引用。
|
||||
|
||||
你可以通过定义类之间的关系为弱引用或者无主引用,以此替代强引用,从而解决循环强引用的问题。具体的过程在[解决类实例之间的循环强引用](#resolving_strong_reference_cycles_between_class_instances)中有描述。不管怎样,在你学习怎样解决循环强引用之前,很有必要了解一下它是怎样产生的。
|
||||
你可以通过定义类之间的关系为弱引用或无主引用,以替代强引用,从而解决循环强引用的问题。具体的过程在[解决类实例之间的循环强引用](#resolving_strong_reference_cycles_between_class_instances)中有描述。不管怎样,在你学习怎样解决循环强引用之前,很有必要了解一下它是怎样产生的。
|
||||
|
||||
下面展示了一个不经意产生循环强引用的例子。例子定义了两个类:`Person`和`Apartment`,用来建模公寓和它其中的居民:
|
||||
|
||||
@ -109,7 +111,7 @@ class Person {
|
||||
let name: String
|
||||
init(name: String) { self.name = name }
|
||||
var apartment: Apartment?
|
||||
deinit { println("\(name) is being deinitialized") }
|
||||
deinit { print("\(name) is being deinitialized") }
|
||||
}
|
||||
```
|
||||
|
||||
@ -118,7 +120,7 @@ class Apartment {
|
||||
let number: Int
|
||||
init(number: Int) { self.number = number }
|
||||
var tenant: Person?
|
||||
deinit { println("Apartment #\(number) is being deinitialized") }
|
||||
deinit { print("Apartment #\(number) is being deinitialized") }
|
||||
}
|
||||
```
|
||||
|
||||
@ -128,14 +130,14 @@ class Apartment {
|
||||
|
||||
这两个类都定义了析构函数,用以在类实例被析构的时候输出信息。这让你能够知晓`Person`和`Apartment`的实例是否像预期的那样被销毁。
|
||||
|
||||
接下来的代码片段定义了两个可选类型的变量`john`和`number73`,并分别被设定为下面的`Apartment`和`Person`的实例。这两个变量都被初始化为`nil`,并为可选的:
|
||||
接下来的代码片段定义了两个可选类型的变量`john`和`number73`,并分别被设定为下面的`Apartment`和`Person`的实例。这两个变量都被初始化为`nil`,这正是可选的优点:
|
||||
|
||||
```swift
|
||||
var john: Person?
|
||||
var number73: Apartment?
|
||||
```
|
||||
|
||||
现在你可以创建特定的`Person`和`Apartment`实例并将类实例赋值给`john`和`number73`变量:
|
||||
现在你可以创建特定的`Person`和`Apartment`实例并将赋值给`john`和`number73`变量:
|
||||
|
||||
```swift
|
||||
john = Person(name: "John Appleseed")
|
||||
@ -157,14 +159,14 @@ number73!.tenant = john
|
||||
|
||||

|
||||
|
||||
不幸的是,将这两个实例关联在一起之后,一个循环强引用被创建了。`Person`实例现在有了一个指向`Apartment`实例的强引用,而`Apartment`实例也有了一个指向`Person`实例的强引用。因此,当你断开`john`和`number73`变量所持有的强引用时,引用计数并不会降为 0,实例也不会被 ARC 销毁:
|
||||
不幸的是,这两个实例关联后会产生一个循环强引用。`Person`实例现在有了一个指向`Apartment`实例的强引用,而`Apartment`实例也有了一个指向`Person`实例的强引用。因此,当你断开`john`和`number73`变量所持有的强引用时,引用计数并不会降为 0,实例也不会被 ARC 销毁:
|
||||
|
||||
```swift
|
||||
john = nil
|
||||
number73 = nil
|
||||
```
|
||||
|
||||
注意,当你把这两个变量设为`nil`时,没有任何一个析构函数被调用。强引用循环阻止了`Person`和`Apartment`类实例的销毁,并在你的应用程序中造成了内存泄漏。
|
||||
注意,当你把这两个变量设为`nil`时,没有任何一个析构函数被调用。循环强引用会一直阻止`Person`和`Apartment`类实例的销毁,这就在你的应用程序中造成了内存泄漏。
|
||||
|
||||
在你将`john`和`number73`赋值为`nil`后,强引用关系如下图:
|
||||
|
||||
@ -179,20 +181,20 @@ Swift 提供了两种办法用来解决你在使用类的属性时所遇到的
|
||||
|
||||
弱引用和无主引用允许循环引用中的一个实例引用另外一个实例而不保持强引用。这样实例能够互相引用而不产生循环强引用。
|
||||
|
||||
对于生命周期中会变为`nil`的实例使用弱引用。相反的,对于初始化赋值后再也不会被赋值为`nil`的实例,使用无主引用。
|
||||
对于生命周期中会变为`nil`的实例使用弱引用。相反地,对于初始化赋值后再也不会被赋值为`nil`的实例,使用无主引用。
|
||||
|
||||
### 弱引用
|
||||
|
||||
弱引用不会牢牢保持住引用的实例,并且不会阻止 ARC 销毁被引用的实例。这种行为阻止了引用变为循环强引用。声明属性或者变量时,在前面加上`weak`关键字表明这是一个弱引用。
|
||||
弱引用不会对其引用的实例保持强引用,因而不会阻止 ARC 销毁被引用的实例。这个特性阻止了引用变为循环强引用。声明属性或者变量时,在前面加上`weak`关键字表明这是一个弱引用。
|
||||
|
||||
在实例的生命周期中,如果某些时候引用没有值,那么弱引用可以阻止循环强引用。如果引用总是有值,则可以使用无主引用,在[无主引用](#2)中有描述。在上面`Apartment`的例子中,一个公寓的生命周期中,有时是没有“居民”的,因此适合使用弱引用来解决循环强引用。
|
||||
在实例的生命周期中,如果某些时候引用没有值,那么弱引用可以避免循环强引用。如果引用总是有值,则可以使用无主引用,在[无主引用](#2)中有描述。在上面`Apartment`的例子中,一个公寓的生命周期中,有时是没有“居民”的,因此适合使用弱引用来解决循环强引用。
|
||||
|
||||
> 注意:
|
||||
> 弱引用必须被声明为变量,表明其值能在运行时被修改。弱引用不能被声明为常量。
|
||||
|
||||
因为弱引用可以没有值,你必须将每一个弱引用声明为可选类型。可选类型是在 Swift 语言中推荐的用来表示可能没有值的类型。
|
||||
因为弱引用可以没有值,你必须将每一个弱引用声明为可选类型。在 Swift 中,推荐使用可选类型描述可能没有值的类型。
|
||||
|
||||
因为弱引用不会保持所引用的实例,即使引用存在,实例也有可能被销毁。因此,ARC 会在引用的实例被销毁后自动将其赋值为`nil`。你可以像其他可选值一样,检查弱引用的值是否存在,你永远也不会遇到被销毁了而不存在的实例。
|
||||
因为弱引用不会保持所引用的实例,即使引用存在,实例也有可能被销毁。因此,ARC 会在引用的实例被销毁后自动将其赋值为`nil`。你可以像其他可选值一样,检查弱引用的值是否存在,你将永远不会访问已销毁的实例的引用。
|
||||
|
||||
下面的例子跟上面`Person`和`Apartment`的例子一致,但是有一个重要的区别。这一次,`Apartment`的`tenant`属性被声明为弱引用:
|
||||
|
||||
@ -201,7 +203,7 @@ class Person {
|
||||
let name: String
|
||||
init(name: String) { self.name = name }
|
||||
var apartment: Apartment?
|
||||
deinit { println("\(name) is being deinitialized") }
|
||||
deinit { print("\(name) is being deinitialized") }
|
||||
}
|
||||
```
|
||||
|
||||
@ -210,11 +212,11 @@ class Apartment {
|
||||
let number: Int
|
||||
init(number: Int) { self.number = number }
|
||||
weak var tenant: Person?
|
||||
deinit { println("Apartment #\(number) is being deinitialized") }
|
||||
deinit { print("Apartment #\(number) is being deinitialized") }
|
||||
}
|
||||
```
|
||||
|
||||
然后跟之前一样,建立两个变量(john和number73)之间的强引用,并关联两个实例:
|
||||
然后跟之前一样,建立两个变量(`john`和`number73`)之间的强引用,并关联两个实例:
|
||||
|
||||
```swift
|
||||
var john: Person?
|
||||
@ -264,11 +266,11 @@ number73 = nil
|
||||
|
||||
> 注意:
|
||||
>如果你试图在实例被销毁后,访问该实例的无主引用,会触发运行时错误。使用无主引用,你必须确保引用始终指向一个未销毁的实例。
|
||||
> 还需要注意的是如果你试图访问实例已经被销毁的无主引用,程序会直接崩溃,而不会发生无法预期的行为。所以你应当避免这样的事情发生。
|
||||
> 还需要注意的是如果你试图访问实例已经被销毁的无主引用,Swift 确保程序会直接崩溃,而不会发生无法预期的行为。所以你应当避免这样的事情发生。
|
||||
|
||||
下面的例子定义了两个类,`Customer`和`CreditCard`,模拟了银行客户和客户的信用卡。这两个类中,每一个都将另外一个类的实例作为自身的属性。这种关系会潜在的创造循环强引用。
|
||||
下面的例子定义了两个类,`Customer`和`CreditCard`,模拟了银行客户和客户的信用卡。这两个类中,每一个都将另外一个类的实例作为自身的属性。这种关系可能会造成循环强引用。
|
||||
|
||||
`Customer`和`CreditCard`之间的关系与前面弱引用例子中`Apartment`和`Person`的关系截然不同。在这个数据模型中,一个客户可能有或者没有信用卡,但是一张信用卡总是关联着一个客户。为了表示这种关系,`Customer`类有一个可选类型的`card`属性,但是`CreditCard`类有一个非可选类型的`customer`属性。
|
||||
`Customer`和`CreditCard`之间的关系与前面弱引用例子中`Apartment`和`Person`的关系略微不同。在这个数据模型中,一个客户可能有或者没有信用卡,但是一张信用卡总是关联着一个客户。为了表示这种关系,`Customer`类有一个可选类型的`card`属性,但是`CreditCard`类有一个非可选类型的`customer`属性。
|
||||
|
||||
此外,只能通过将一个`number`值和`customer`实例传递给`CreditCard`构造函数的方式来创建`CreditCard`实例。这样可以确保当创建`CreditCard`实例时总是有一个`customer`实例与之关联。
|
||||
|
||||
@ -281,22 +283,25 @@ class Customer {
|
||||
init(name: String) {
|
||||
self.name = name
|
||||
}
|
||||
deinit { println("\(name) is being deinitialized") }
|
||||
deinit { print("\(name) is being deinitialized") }
|
||||
}
|
||||
```
|
||||
|
||||
```swift
|
||||
class CreditCard {
|
||||
let number: Int
|
||||
let number: UInt64
|
||||
unowned let customer: Customer
|
||||
init(number: Int, customer: Customer) {
|
||||
init(number: UInt64, customer: Customer) {
|
||||
self.number = number
|
||||
self.customer = customer
|
||||
}
|
||||
deinit { println("Card #\(number) is being deinitialized") }
|
||||
deinit { print("Card #\(number) is being deinitialized") }
|
||||
}
|
||||
```
|
||||
|
||||
> 注意:
|
||||
> `CreditCard`类的`number`属性被定义为`UInt64`类型而不是`Int`类型,以确保`number`属性的存储量在32位和64位系统上都能足够容纳16位的卡号。
|
||||
|
||||
下面的代码片段定义了一个叫`john`的可选类型`Customer`变量,用来保存某个特定客户的引用。由于是可选类型,所以变量被初始化为`nil`。
|
||||
|
||||
```swift
|
||||
@ -336,18 +341,18 @@ john = nil
|
||||
|
||||
`Person`和`Apartment`的例子展示了两个属性的值都允许为`nil`,并会潜在的产生循环强引用。这种场景最适合用弱引用来解决。
|
||||
|
||||
`Customer`和`CreditCard`的例子展示了一个属性的值允许为`nil`,而另一个属性的值不允许为`nil`,并会潜在的产生循环强引用。这种场景最适合通过无主引用来解决。
|
||||
`Customer`和`CreditCard`的例子展示了一个属性的值允许为`nil`,而另一个属性的值不允许为`nil`,这也可能会产生循环强引用。这种场景最适合通过无主引用来解决。
|
||||
|
||||
然而,存在着第三种场景,在这种场景中,两个属性都必须有值,并且初始化完成后不能为`nil`。在这种场景中,需要一个类使用无主属性,而另外一个类使用隐式解析可选属性。
|
||||
然而,存在着第三种场景,在这种场景中,两个属性都必须有值,并且初始化完成后永远不会为`nil`。在这种场景中,需要一个类使用无主属性,而另外一个类使用隐式解析可选属性。
|
||||
|
||||
这使两个属性在初始化完成后能被直接访问(不需要可选展开),同时避免了循环引用。这一节将为你展示如何建立这种关系。
|
||||
|
||||
下面的例子定义了两个类,`Country`和`City`,每个类将另外一个类的实例保存为属性。在这个模型中,每个国家必须有首都,而每一个城市必须属于一个国家。为了实现这种关系,`Country`类拥有一个`capitalCity`属性,而`City`类有一个`country`属性:
|
||||
下面的例子定义了两个类,`Country`和`City`,每个类将另外一个类的实例保存为属性。在这个模型中,每个国家必须有首都,每个城市必须属于一个国家。为了实现这种关系,`Country`类拥有一个`capitalCity`属性,而`City`类有一个`country`属性:
|
||||
|
||||
```swift
|
||||
class Country {
|
||||
let name: String
|
||||
let capitalCity: City!
|
||||
var capitalCity: City!
|
||||
init(name: String, capitalName: String) {
|
||||
self.name = name
|
||||
self.capitalCity = City(name: capitalName, country: self)
|
||||
@ -370,7 +375,7 @@ class City {
|
||||
|
||||
`Country`的构造函数调用了`City`的构造函数。然而,只有`Country`的实例完全初始化完后,`Country`的构造函数才能把`self`传给`City`的构造函数。([在两段式构造过程中有具体描述](14_Initialization.html))
|
||||
|
||||
为了满足这种需求,通过在类型结尾处加上感叹号(City!)的方式,将`Country`的`capitalCity`属性声明为隐式解析可选类型的属性。这表示像其他可选类型一样,`capitalCity`属性的默认值为`nil`,但是不需要展开它的值就能访问它。([在隐式解析可选类型中有描述](01_The_Basics.html))
|
||||
为了满足这种需求,通过在类型结尾处加上感叹号(`City!`)的方式,将`Country`的`capitalCity`属性声明为隐式解析可选类型的属性。这表示像其他可选类型一样,`capitalCity`属性的默认值为`nil`,但是不需要展开它的值就能访问它。([在隐式解析可选类型中有描述](01_The_Basics.html))
|
||||
|
||||
由于`capitalCity`默认值为`nil`,一旦`Country`的实例在构造函数中给`name`属性赋值后,整个初始化过程就完成了。这代表一旦`name`属性被赋值后,`Country`的构造函数就能引用并传递隐式的`self`。`Country`的构造函数在赋值`capitalCity`时,就能将`self`作为参数传递给`City`的构造函数。
|
||||
|
||||
@ -378,7 +383,7 @@ class City {
|
||||
|
||||
```swift
|
||||
var country = Country(name: "Canada", capitalName: "Ottawa")
|
||||
println("\(country.name)'s capital city is called \(country.capitalCity.name)")
|
||||
print("\(country.name)'s capital city is called \(country.capitalCity.name)")
|
||||
// prints "Canada's capital city is called Ottawa"
|
||||
```
|
||||
|
||||
@ -387,13 +392,13 @@ println("\(country.name)'s capital city is called \(country.capitalCity.name)")
|
||||
<a name="strong_reference_cycles_for_closures"></a>
|
||||
##闭包引起的循环强引用
|
||||
|
||||
前面我们看到了循环强引用环是在两个类实例属性互相保持对方的强引用时产生的,还知道了如何用弱引用和无主引用来打破循环强引用。
|
||||
前面我们看到了循环强引用是在两个类实例属性互相保持对方的强引用时产生的,还知道了如何用弱引用和无主引用来打破这些循环强引用。
|
||||
|
||||
循环强引用还会发生在当你将一个闭包赋值给类实例的某个属性,并且这个闭包体中又使用了实例。这个闭包体中可能访问了实例的某个属性,例如`self.someProperty`,或者闭包中调用了实例的某个方法,例如`self.someMethod`。这两种情况都导致了闭包 “捕获" `self`,从而产生了循环强引用。
|
||||
循环强引用还会发生在当你将一个闭包赋值给类实例的某个属性,并且这个闭包体中又使用了这个类实例。这个闭包体中可能访问了实例的某个属性,例如`self.someProperty`,或者闭包中调用了实例的某个方法,例如`self.someMethod`。这两种情况都导致了闭包 “捕获" `self`,从而产生了循环强引用。
|
||||
|
||||
循环强引用的产生,是因为闭包和类相似,都是引用类型。当你把一个闭包赋值给某个属性时,你也把一个引用赋值给了这个闭包。实质上,这跟之前的问题是一样的-两个强引用让彼此一直有效。但是,和两个类实例不同,这次一个是类实例,另一个是闭包。
|
||||
|
||||
Swift 提供了一种优雅的方法来解决这个问题,称之为闭包占用列表(closuer capture list)。同样的,在学习如何用闭包占用列表破坏循环强引用之前,先来了解一下循环强引用是如何产生的,这对我们是很有帮助的。
|
||||
Swift 提供了一种优雅的方法来解决这个问题,称之为闭包捕获列表(closuer capture list)。同样的,在学习如何用闭包捕获列表破坏循环强引用之前,先来了解一下这里的循环强引用是如何产生的,这对我们很有帮助。
|
||||
|
||||
下面的例子为你展示了当一个闭包引用了`self`后是如何产生一个循环强引用的。例子中定义了一个叫`HTMLElement`的类,用一种简单的模型表示 HTML 中的一个单独的元素:
|
||||
|
||||
@ -403,7 +408,7 @@ class HTMLElement {
|
||||
let name: String
|
||||
let text: String?
|
||||
|
||||
lazy var asHTML: () -> String = {
|
||||
lazy var asHTML: Void -> String = {
|
||||
if let text = self.text {
|
||||
return "<\(self.name)>\(text)</\(self.name)>"
|
||||
} else {
|
||||
@ -417,7 +422,7 @@ class HTMLElement {
|
||||
}
|
||||
|
||||
deinit {
|
||||
println("\(name) is being deinitialized")
|
||||
print("\(name) is being deinitialized")
|
||||
}
|
||||
|
||||
}
|
||||
@ -425,9 +430,9 @@ class HTMLElement {
|
||||
|
||||
`HTMLElement`类定义了一个`name`属性来表示这个元素的名称,例如代表段落的"p",或者代表换行的"br"。`HTMLElement`还定义了一个可选属性`text`,用来设置和展现 HTML 元素的文本。
|
||||
|
||||
除了上面的两个属性,`HTMLElement`还定义了一个`lazy`属性`asHTML`。这个属性引用了一个闭包,将`name`和`text`组合成 HTML 字符串片段。该属性是`() -> String`类型,或者可以理解为“一个没有参数,返回`String`的函数”。
|
||||
除了上面的两个属性,`HTMLElement`还定义了一个`lazy`属性`asHTML`。这个属性引用了一个将`name`和`text`组合成 HTML 字符串片段的闭包。该属性是`Void -> String`类型,或者可以理解为“一个没有参数,返回`String`的函数”。
|
||||
|
||||
默认情况下,闭包赋值给了`asHTML`属性,这个闭包返回一个代表 HTML 标签的字符串。如果`text`值存在,该标签就包含可选值`text`;如果`text`不存在,该标签就不包含文本。对于段落元素,根据`text`是"some text"还是`nil`,闭包会返回"`<p>some text</p>`"或者"`<p />`"。
|
||||
默认情况下,闭包赋值给了`asHTML`属性,这个闭包返回一个代表 HTML 标签的字符串。如果`text`值存在,该标签就包含可选值`text`;如果`text`不存在,该标签就不包含文本。对于段落元素,根据`text`是`"some text"`还是`nil`,闭包会返回"`<p>some text</p>`"或者"`<p />`"。
|
||||
|
||||
可以像实例方法那样去命名、使用`asHTML`属性。然而,由于`asHTML`是闭包而不是实例方法,如果你想改变特定元素的 HTML 处理的话,可以用自定义的闭包来取代默认值。
|
||||
|
||||
@ -440,7 +445,7 @@ class HTMLElement {
|
||||
|
||||
```swift
|
||||
var paragraph: HTMLElement? = HTMLElement(name: "p", text: "hello, world")
|
||||
println(paragraph!.asHTML())
|
||||
print(paragraph!.asHTML())
|
||||
// prints"hello, world"
|
||||
```
|
||||
|
||||
@ -470,38 +475,38 @@ paragraph = nil
|
||||
在定义闭包时同时定义捕获列表作为闭包的一部分,通过这种方式可以解决闭包和类实例之间的循环强引用。捕获列表定义了闭包体内捕获一个或者多个引用类型的规则。跟解决两个类实例间的循环强引用一样,声明每个捕获的引用为弱引用或无主引用,而不是强引用。应当根据代码关系来决定使用弱引用还是无主引用。
|
||||
|
||||
>注意:
|
||||
Swift 有如下要求:只要在闭包内使用`self`的成员,就要用`self.someProperty`或者`self.someMethod`(而不只是`someProperty`或`someMethod`)。这提醒你可能会不小心就捕获了`self`。
|
||||
Swift 有如下要求:只要在闭包内使用`self`的成员,就要用`self.someProperty`或者`self.someMethod`(而不只是`someProperty`或`someMethod`)。这提醒你可能会一不小心就捕获了`self`。
|
||||
|
||||
###定义捕获列表
|
||||
|
||||
捕获列表中的每个元素都是由`weak`或者`unowned`关键字和实例的引用(如`self`或`someInstance`)成对组成。每一对都在方括号中,通过逗号分开。
|
||||
捕获列表中的每一项都由一对元素组成,一个元素是`weak`或`unowned`关键字,另一个元素是类实例的引用(如`self`)或初始化过的变量(如`delegate = self.delegate!`)。这些项在方括号中用逗号分开。
|
||||
|
||||
捕获列表放置在闭包参数列表和返回类型之前:
|
||||
如果闭包有参数列表和返回类型,把捕获列表放在它们前面:
|
||||
|
||||
```swift
|
||||
lazy var someClosure: (Int, String) -> String = {
|
||||
[unowned self] (index: Int, stringToProcess: String) -> String in
|
||||
[unowned self, weak delegate = self.delegate!] (index: Int, stringToProcess: String) -> String in
|
||||
// closure body goes here
|
||||
}
|
||||
```
|
||||
|
||||
如果闭包没有指定参数列表或者返回类型,则可以通过上下文推断,那么可以捕获列表放在闭包开始的地方,跟着是关键字`in`:
|
||||
如果闭包没有指明参数列表或者返回类型,即它们会通过上下文推断,那么可以把捕获列表和关键字`in`放在闭包最开始的地方:
|
||||
|
||||
```swift
|
||||
lazy var someClosure: () -> String = {
|
||||
[unowned self] in
|
||||
lazy var someClosure: Void -> String = {
|
||||
[unowned self, weak delegate = self.delegate!] in
|
||||
// closure body goes here
|
||||
}
|
||||
```
|
||||
|
||||
###弱引用和无主引用
|
||||
|
||||
当闭包和捕获的实例总是互相引用时并且总是同时销毁时,将闭包内的捕获定义为无主引用。
|
||||
在闭包和捕获的实例总是互相引用时并且总是同时销毁时,将闭包内的捕获定义为无主引用。
|
||||
|
||||
相反的,当捕获引用有时可能会是`nil`时,将闭包内的捕获定义为弱引用。弱引用总是可选类型,并且当引用的实例被销毁后,弱引用的值会自动置为`nil`。这使我们可以在闭包内检查它们是否存在。
|
||||
相反的,在被捕获的引用可能会变为`nil`时,将闭包内的捕获定义为弱引用。弱引用总是可选类型,并且当引用的实例被销毁后,弱引用的值会自动置为`nil`。这使我们可以在闭包体内检查它们是否存在。
|
||||
|
||||
>注意:
|
||||
如果捕获的引用绝对不会置为`nil`,应该用无主引用,而不是弱引用。
|
||||
如果被捕获的引用绝对不会变为`nil`,应该用无主引用,而不是弱引用。
|
||||
|
||||
前面的`HTMLElement`例子中,无主引用是正确的解决循环强引用的方法。这样编写`HTMLElement`类来避免循环强引用:
|
||||
|
||||
@ -511,7 +516,7 @@ class HTMLElement {
|
||||
let name: String
|
||||
let text: String?
|
||||
|
||||
lazy var asHTML: () -> String = {
|
||||
lazy var asHTML: Void -> String = {
|
||||
[unowned self] in
|
||||
if let text = self.text {
|
||||
return "<\(self.name)>\(text)</\(self.name)>"
|
||||
@ -526,19 +531,19 @@ class HTMLElement {
|
||||
}
|
||||
|
||||
deinit {
|
||||
println("\(name) is being deinitialized")
|
||||
print("\(name) is being deinitialized")
|
||||
}
|
||||
|
||||
}
|
||||
```
|
||||
|
||||
上面的`HTMLElement`实现和之前的实现一致,只是在`asHTML`闭包中多了一个捕获列表。这里,捕获列表是`[unowned self]`,表示“用无主引用而不是强引用来捕获`self`”。
|
||||
上面的`HTMLElement`实现和之前的实现一致,除了在`asHTML`闭包中多了一个捕获列表。这里,捕获列表是`[unowned self]`,表示“用无主引用而不是强引用来捕获`self`”。
|
||||
|
||||
和之前一样,我们可以创建并打印`HTMLElement`实例:
|
||||
|
||||
```swift
|
||||
var paragraph: HTMLElement? = HTMLElement(name: "p", text: "hello, world")
|
||||
println(paragraph!.asHTML())
|
||||
print(paragraph!.asHTML())
|
||||
// prints "<p>hello, world</p>"
|
||||
```
|
||||
|
||||
|
||||
@ -76,7 +76,7 @@ struct BlackjackCard {
|
||||
|
||||
```swift
|
||||
let theAceOfSpades = BlackjackCard(rank: .Ace, suit: .Spades)
|
||||
println("theAceOfSpades: \(theAceOfSpades.description)")
|
||||
print("theAceOfSpades: \(theAceOfSpades.description)")
|
||||
// 打印出 "theAceOfSpades: suit is ♠, value is 1 or 11"
|
||||
```
|
||||
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
> 翻译:[xiehurricane](https://github.com/xiehurricane)
|
||||
> 校对:[happyming](https://github.com/happyming)
|
||||
> 校对:[happyming](https://github.com/happyming) [yangsiy](https://github.com/yangsiy)
|
||||
|
||||
# 类型转换(Type Casting)
|
||||
-----------------
|
||||
@ -16,14 +16,14 @@ _类型转换_可以判断实例的类型,也可以将实例看做是其父类
|
||||
|
||||
类型转换在 Swift 中使用 `is` 和 `as` 操作符实现。这两个操作符提供了一种简单达意的方式去检查值的类型或者转换它的类型。
|
||||
|
||||
你也可以用来检查一个类是否实现了某个协议,就像在 [Checking for Protocol Conformance](Protocols.html#//apple_ref/doc/uid/TP40014097-CH25-XID_363)部分讲述的一样。
|
||||
你也可以用它来检查一个类是否实现了某个协议,就像在 [Checking for Protocol Conformance](Protocols.html#//apple_ref/doc/uid/TP40014097-CH25-XID_363)部分讲述的一样。
|
||||
|
||||
<a name="defining_a_class_hierarchy_for_type_casting"></a>
|
||||
## 定义一个类层次作为例子
|
||||
|
||||
你可以将它用在类和子类的层次结构上,检查特定类实例的类型并且转换这个类实例的类型成为这个层次结构中的其他类型。这下面的三个代码段定义了一个类层次和一个包含了几个这些类实例的数组,作为类型转换的例子。
|
||||
你可以将类型转换用在类和子类的层次结构上,检查特定类实例的类型并且转换这个类实例的类型成为这个层次结构中的其他类型。下面的三个代码段定义了一个类层次和一个包含了几个这些类实例的数组,作为类型转换的例子。
|
||||
|
||||
第一个代码片段定义了一个新的基础类`MediaItem`。这个类为任何出现在数字媒体库的媒体项提供基础功能。特别的,它声明了一个 `String` 类型的 `name` 属性,和一个`init name`初始化器。(它假定所有的媒体项都有个名称。)
|
||||
第一个代码片段定义了一个新的基础类 `MediaItem`。这个类为任何出现在数字媒体库的媒体项提供基础功能。特别的,它声明了一个 `String` 类型的 `name` 属性,和一个 `init name` 初始化器。(假定所有的媒体项都有个名称。)
|
||||
|
||||
```swift
|
||||
class MediaItem {
|
||||
@ -34,7 +34,7 @@ class MediaItem {
|
||||
}
|
||||
```
|
||||
|
||||
下一个代码段定义了 `MediaItem` 的两个子类。第一个子类`Movie`,在父类(或者说基类)的基础上增加了一个 `director`(导演) 属性,和相应的初始化器。第二个类在父类的基础上增加了一个 `artist`(艺术家) 属性,和相应的初始化器:
|
||||
下一个代码段定义了 `MediaItem` 的两个子类。第一个子类 `Movie` 封装了与电影相关的额外信息,在父类(或者说基类)的基础上增加了一个 `director`(导演)属性,和相应的初始化器。第二个子类 `Song`,在父类的基础上增加了一个 `artist`(艺术家)属性,和相应的初始化器:
|
||||
|
||||
```swift
|
||||
class Movie: MediaItem {
|
||||
@ -54,7 +54,7 @@ class Song: MediaItem {
|
||||
}
|
||||
```
|
||||
|
||||
最后一个代码段创建了一个数组常量 `library`,包含两个`Movie`实例和三个`Song`实例。`library`的类型是在它被初始化时根据它数组中所包含的内容推断来的。Swift 的类型检测器能够演绎出`Movie` 和 `Song` 有共同的父类 `MediaItem` ,所以它推断出 `[MediaItem]` 类作为 `library` 的类型。
|
||||
最后一个代码段创建了一个数组常量 `library`,包含两个 `Movie` 实例和三个 `Song` 实例。`library` 的类型是在它被初始化时根据它数组中所包含的内容推断来的。Swift的类型检测器能够推理出 `Movie` 和 `Song` 有共同的父类 `MediaItem`,所以它推断出 `[MediaItem]` 类作为 `library` 的类型。
|
||||
|
||||
```swift
|
||||
let library = [
|
||||
@ -67,7 +67,7 @@ let library = [
|
||||
// the type of "library" is inferred to be [MediaItem]
|
||||
```
|
||||
|
||||
在幕后`library` 里存储的媒体项依然是 `Movie` 和 `Song` 类型的,但是,若你迭代它,取出的实例会是 `MediaItem` 类型的,而不是 `Movie` 和 `Song` 类型的。为了让它们作为它们本来的类型工作,你需要检查它们的类型或者向下转换它们的类型到其它类型,就像下面描述的一样。
|
||||
在幕后 `library` 里存储的媒体项依然是 `Movie` 和 `Song` 类型的。但是,若你迭代它,依次取出的实例会是 `MediaItem` 类型的,而不是 `Movie` 和 `Song` 类型。为了让它们作为原本的类型工作,你需要检查它们的类型或者向下转换它们到其它类型,就像下面描述的一样。
|
||||
|
||||
<a name="checking_type"></a>
|
||||
## 检查类型(Checking Type)
|
||||
@ -88,7 +88,7 @@ for item in library {
|
||||
}
|
||||
}
|
||||
|
||||
println("Media library contains \(movieCount) movies and \(songCount) songs")
|
||||
print("Media library contains \(movieCount) movies and \(songCount) songs")
|
||||
// prints "Media library contains 2 movies and 3 songs"
|
||||
```
|
||||
|
||||
@ -102,24 +102,24 @@ Song`检查item是否为`Song`类型的实例。在循环结束后,`movieCount
|
||||
<a name="downcasting"></a>
|
||||
## 向下转型(Downcasting)
|
||||
|
||||
某类型的一个常量或变量可能在幕后实际上属于一个子类。你可以相信,上面就是这种情况。你可以尝试向下转到它的子类型,用类型转换操作符(`as`)
|
||||
某类型的一个常量或变量可能在幕后实际上属于一个子类。当确定是这种情况时,你可以尝试向下转到它的子类型,用类型转换操作符(`as?` 或 `as!`)
|
||||
|
||||
因为向下转型可能会失败,类型转型操作符带有两种不同形式。可选形式( optional form) `as?` 返回一个你试图下转成的类型的可选值(optional value)。强制形式 `as` 把试图向下转型和强制解包(force-unwraps)结果作为一个混合动作。
|
||||
因为向下转型可能会失败,类型转型操作符带有两种不同形式。条件形式(conditional form) `as?` 返回一个你试图向下转成的类型的可选值(optional value)。强制形式 `as!` 把试图向下转型和强制解包(force-unwraps)结果作为一个混合动作。
|
||||
|
||||
当你不确定向下转型可以成功时,用类型转换的可选形式(`as?`)。可选形式的类型转换总是返回一个可选值(optional value),并且若下转是不可能的,可选值将是 `nil` 。这使你能够检查向下转型是否成功。
|
||||
当你不确定向下转型可以成功时,用类型转换的条件形式(`as?`)。条件形式的类型转换总是返回一个可选值(optional value),并且若下转是不可能的,可选值将是 `nil`。这使你能够检查向下转型是否成功。
|
||||
|
||||
只有你可以确定向下转型一定会成功时,才使用强制形式。当你试图向下转型为一个不正确的类型时,强制形式的类型转换会触发一个运行时错误。
|
||||
只有你可以确定向下转型一定会成功时,才使用强制形式(`as!`)。当你试图向下转型为一个不正确的类型时,强制形式的类型转换会触发一个运行时错误。
|
||||
|
||||
下面的例子,迭代了`library`里的每一个 `MediaItem` ,并打印出适当的描述。要这样做,`item`需要真正作为`Movie` 或 `Song`的类型来使用。不仅仅是作为 `MediaItem`。为了能够使用`Movie` 或 `Song`的 `director` 或 `artist`属性,这是必要的。
|
||||
下面的例子,迭代了 `library` 里的每一个 `MediaItem`,并打印出适当的描述。要这样做,`item` 需要真正作为 `Movie` 或 `Song` 的类型来使用,不仅仅是作为 `MediaItem`。为了能够在描述中使用 `Movie` 或 `Song` 的 `director` 或 `artist` 属性,这是必要的。
|
||||
|
||||
在这个示例中,数组中的每一个`item`可能是 `Movie` 或 `Song`。 事前你不知道每个`item`的真实类型,所以这里使用可选形式的类型转换 (`as?`)去检查循环里的每次下转。
|
||||
在这个示例中,数组中的每一个 `item` 可能是 `Movie` 或 `Song`。事前你不知道每个 `item` 的真实类型,所以这里使用条件形式的类型转换(`as?`)去检查循环里的每次下转。
|
||||
|
||||
```swift
|
||||
for item in library {
|
||||
if let movie = item as? Movie {
|
||||
println("Movie: '\(movie.name)', dir. \(movie.director)")
|
||||
print("Movie: '\(movie.name)', dir. \(movie.director)")
|
||||
} else if let song = item as? Song {
|
||||
println("Song: '\(song.name)', by \(song.artist)")
|
||||
print("Song: '\(song.name)', by \(song.artist)")
|
||||
}
|
||||
}
|
||||
|
||||
@ -131,18 +131,18 @@ for item in library {
|
||||
```
|
||||
|
||||
示例首先试图将 `item` 下转为 `Movie`。因为 `item` 是一个 `MediaItem`
|
||||
类型的实例,它可能是一个`Movie`;同样,它可能是一个 `Song`,或者仅仅是基类
|
||||
`MediaItem`。因为不确定,`as?`形式在试图下转时将返还一个可选值。 `item as Movie` 的返回值是`Movie?`类型或 “optional `Movie`”。
|
||||
类型的实例,它可能是一个 `Movie`;同样,它也可能是一个 `Song`,或者仅仅是基类
|
||||
`MediaItem`。因为不确定,`as?`形式在试图下转时将返回一个可选值。`item as? Movie` 的返回值是 `Movie?` 或 “可选 `Movie`”类型。
|
||||
|
||||
当向下转型为 `Movie` 应用在两个 `Song`
|
||||
实例时将会失败。为了处理这种情况,上面的例子使用了可选绑定(optional binding)来检查可选 `Movie` 真的包含一个值(这个是为了判断下转是否成功。)可选绑定是这样写的“`if let movie = item as? Movie`”,可以这样解读:
|
||||
|
||||
“尝试将 `item` 转为 `Movie` 类型。若成功,设置一个新的临时常量 `movie` 来存储返回的可选 `Movie`”
|
||||
|
||||
若向下转型成功,然后`movie`的属性将用于打印一个`Movie`实例的描述,包括它的导演的名字`director`。当`Song`被找到时,一个相近的原理被用来检测 `Song` 实例和打印它的描述。
|
||||
若向下转型成功,然后 `movie` 的属性将用于打印一个 `Movie` 实例的描述,包括它的导演的名字 `director` 。相近的原理被用来检测 `Song` 实例,当 `Song` 被找到时则打印它的描述(包含 `artist` 的名字)。
|
||||
|
||||
> 注意:
|
||||
转换没有真的改变实例或它的值。潜在的根本的实例保持不变;只是简单地把它作为它被转换成的类来使用。
|
||||
> 转换没有真的改变实例或它的值。潜在的根本的实例保持不变;只是简单地把它作为它被转换成的类来使用。
|
||||
|
||||
<a name="type_casting_for_any_and_anyobject"></a>
|
||||
## `Any`和`AnyObject`的类型转换
|
||||
@ -153,11 +153,11 @@ Swift为不确定类型提供了两种特殊类型别名:
|
||||
* `Any`可以表示任何类型,包括方法类型(function types)。
|
||||
|
||||
> 注意:
|
||||
只有当你明确的需要它的行为和功能时才使用`Any`和`AnyObject`。在你的代码里使用你期望的明确的类型总是更好的。
|
||||
> 只有当你明确的需要它的行为和功能时才使用`Any`和`AnyObject`。在你的代码里使用你期望的明确的类型总是更好的。
|
||||
|
||||
### `AnyObject`类型
|
||||
|
||||
当需要在工作中使用 Cocoa APIs,它一般接收一个`[AnyObject]`类型的数组,或者说“一个任何对象类型的数组”。这是因为 Objective-C 没有明确的类型化数组。但是,你常常可以确定包含在仅从你知道的 API 信息提供的这样一个数组中的对象的类型。
|
||||
当在工作中使用 Cocoa APIs,我们一般会接收一个`[AnyObject]`类型的数组,或者说“一个任何对象类型的数组”。这是因为 Objective-C 没有明确的类型化数组。但是,你常常可以从 API 提供的信息中清晰地确定数组中对象的类型。
|
||||
|
||||
在这些情况下,你可以使用强制形式的类型转换(`as`)来下转在数组中的每一项到比 `AnyObject` 更明确的类型,不需要可选解析(optional unwrapping)。
|
||||
|
||||
@ -171,23 +171,23 @@ let someObjects: [AnyObject] = [
|
||||
]
|
||||
```
|
||||
|
||||
因为知道这个数组只包含 `Movie` 实例,你可以直接用(`as`)下转并解包到不可选的`Movie`类型(ps:其实就是我们常用的正常类型,这里是为了和可选类型相对比)。
|
||||
因为知道这个数组只包含 `Movie` 实例,你可以直接用(`as!`)下转并解包到不可选的`Movie`类型:
|
||||
|
||||
```swift
|
||||
for object in someObjects {
|
||||
let movie = object as Movie
|
||||
println("Movie: '\(movie.name)', dir. \(movie.director)")
|
||||
let movie = object as! Movie
|
||||
print("Movie: '\(movie.name)', dir. \(movie.director)")
|
||||
}
|
||||
// Movie: '2001: A Space Odyssey', dir. Stanley Kubrick
|
||||
// Movie: 'Moon', dir. Duncan Jones
|
||||
// Movie: 'Alien', dir. Ridley Scott
|
||||
```
|
||||
|
||||
为了变为一个更短的形式,下转`someObjects`数组为`[Movie]`类型来代替下转每一项方式。
|
||||
为了变为一个更短的形式,下转`someObjects`数组为`[Movie]`类型来代替下转数组中每一项的方式。
|
||||
|
||||
```swift
|
||||
for movie in someObjects as! [Movie] {
|
||||
println("Movie: '\(movie.name)', dir. \(movie.director)")
|
||||
print("Movie: '\(movie.name)', dir. \(movie.director)")
|
||||
}
|
||||
// Movie: '2001: A Space Odyssey', dir. Stanley Kubrick
|
||||
// Movie: 'Moon', dir. Duncan Jones
|
||||
@ -196,7 +196,7 @@ for movie in someObjects as! [Movie] {
|
||||
|
||||
### `Any`类型
|
||||
|
||||
这里有个示例,使用 `Any` 类型来和混合的不同类型一起工作,包括非`class`类型。它创建了一个可以存储`Any`类型的数组 `things`。
|
||||
这里有个示例,使用 `Any` 类型来和混合的不同类型一起工作,包括方法类型和非 `class` 类型。它创建了一个可以存储`Any`类型的数组 `things`。
|
||||
|
||||
```swift
|
||||
var things = [Any]()
|
||||
@ -211,33 +211,33 @@ things.append(Movie(name: "Ghostbusters", director: "Ivan Reitman"))
|
||||
things.append({ (name: String) -> String in "Hello, \(name)" })
|
||||
```
|
||||
|
||||
`things` 数组包含两个 `Int` 值,2个 `Double` 值,1个 `String` 值,一个元组 `(Double, Double)` ,Ivan Reitman 导演的电影“Ghostbusters”。
|
||||
`things` 数组包含两个 `Int` 值,2个 `Double` 值,1个 `String` 值,一个元组 `(Double, Double)` ,电影“Ghostbusters”,和一个获取 `String` 值并返回另一个 `String` 值的闭包表达式。
|
||||
|
||||
你可以在 `switch` `cases`里用`is` 和 `as` 操作符来发觉只知道是 `Any` 或 `AnyObject`的常量或变量的类型。 下面的示例迭代 `things`数组中的每一项的并用`switch`语句查找每一项的类型。这几种`switch`语句的情形绑定它们匹配的值到一个规定类型的常量,让它们可以打印它们的值:
|
||||
你可以在 `switch` 表达式的cases中使用 `is` 和 `as` 操作符来发觉只知道是 `Any` 或 `AnyObject` 的常量或变量的类型。下面的示例迭代 `things` 数组中的每一项的并用`switch`语句查找每一项的类型。这几种 `switch` 语句的情形绑定它们匹配的值到一个规定类型的常量,让它们的值可以被打印:
|
||||
|
||||
```swift
|
||||
for thing in things {
|
||||
switch thing {
|
||||
case 0 as Int:
|
||||
println("zero as an Int")
|
||||
print("zero as an Int")
|
||||
case 0 as Double:
|
||||
println("zero as a Double")
|
||||
print("zero as a Double")
|
||||
case let someInt as Int:
|
||||
println("an integer value of \(someInt)")
|
||||
print("an integer value of \(someInt)")
|
||||
case let someDouble as Double where someDouble > 0:
|
||||
println("a positive double value of \(someDouble)")
|
||||
print("a positive double value of \(someDouble)")
|
||||
case is Double:
|
||||
println("some other double value that I don't want to print")
|
||||
print("some other double value that I don't want to print")
|
||||
case let someString as String:
|
||||
println("a string value of \"\(someString)\"")
|
||||
print("a string value of \"\(someString)\"")
|
||||
case let (x, y) as (Double, Double):
|
||||
println("an (x, y) point at \(x), \(y)")
|
||||
print("an (x, y) point at \(x), \(y)")
|
||||
case let movie as Movie:
|
||||
println("a movie called '\(movie.name)', dir. \(movie.director)")
|
||||
print("a movie called '\(movie.name)', dir. \(movie.director)")
|
||||
case let stringConverter as String -> String:
|
||||
println(stringConverter("Michael"))
|
||||
print(stringConverter("Michael"))
|
||||
default:
|
||||
println("something else")
|
||||
print("something else")
|
||||
}
|
||||
}
|
||||
|
||||
@ -253,4 +253,4 @@ for thing in things {
|
||||
|
||||
|
||||
> 注意:
|
||||
在一个switch语句的case中使用强制形式的类型转换操作符(as, 而不是 as?)来检查和转换到一个明确的类型。在 switch case 语句的内容中这种检查总是安全的。
|
||||
> 在一个switch语句的case中使用强制形式的类型转换操作符(as, 而不是 as?)来检查和转换到一个明确的类型。在 `switch` case 语句的内容中这种检查总是安全的。
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
|
||||
> 翻译:[takalard](https://github.com/takalard)
|
||||
> 翻译:[takalard](https://github.com/takalard) [SergioChan](https://github.com/SergioChan)
|
||||
> 校对:[lifedim](https://github.com/lifedim)
|
||||
|
||||
# 泛型
|
||||
@ -13,6 +13,7 @@
|
||||
- [类型参数](#type_parameters)
|
||||
- [命名类型参数](#naming_type_parameters)
|
||||
- [泛型类型](#generic_types)
|
||||
- [扩展一个泛型类型](#extending_a_generic_type)
|
||||
- [类型约束](#type_constraints)
|
||||
- [关联类型](#associated_types)
|
||||
- [`Where`语句](#where_clauses)
|
||||
@ -27,7 +28,7 @@
|
||||
这里是一个标准的,非泛型函数`swapTwoInts`,用来交换两个Int值:
|
||||
|
||||
```swift
|
||||
func swapTwoInts(inout a: Int, inout b: Int) {
|
||||
func swapTwoInts(inout a: Int, inout _ b: Int) {
|
||||
let temporaryA = a
|
||||
a = b
|
||||
b = temporaryA
|
||||
@ -36,34 +37,34 @@ func swapTwoInts(inout a: Int, inout b: Int) {
|
||||
|
||||
这个函数使用写入读出(in-out)参数来交换`a`和`b`的值,请参考[写入读出参数](../chapter2/06_Functions.html)。
|
||||
|
||||
`swapTwoInts`函数可以交换`b`的原始值到`a`,也可以交换a的原始值到`b`,你可以调用这个函数交换两个`Int`变量值:
|
||||
`swapTwoInts(_:_:)`函数可以交换`b`的原始值到`a`,也可以交换a的原始值到`b`,你可以调用这个函数交换两个`Int`变量值:
|
||||
|
||||
```swift
|
||||
var someInt = 3
|
||||
var anotherInt = 107
|
||||
swapTwoInts(&someInt, &anotherInt)
|
||||
println("someInt is now \(someInt), and anotherInt is now \(anotherInt)")
|
||||
print("someInt is now \(someInt), and anotherInt is now \(anotherInt)")
|
||||
// 输出 "someInt is now 107, and anotherInt is now 3"
|
||||
```
|
||||
|
||||
|
||||
`swapTwoInts`函数是非常有用的,但是它只能交换`Int`值,如果你想要交换两个`String`或者`Double`,就不得不写更多的函数,如 `swapTwoStrings`和`swapTwoDoublesfunctions `,如同如下所示:
|
||||
`swapTwoInts(_:_:)`函数是非常有用的,但是它只能交换`Int`值,如果你想要交换两个`String`或者`Double`,就不得不写更多的函数,如 `swapTwoStrings`和`swapTwoDoubles(_:_:)`,如同如下所示:
|
||||
|
||||
```swift
|
||||
func swapTwoStrings(inout a: String, inout b: String) {
|
||||
func swapTwoStrings(inout a: String, inout _ b: String) {
|
||||
let temporaryA = a
|
||||
a = b
|
||||
b = temporaryA
|
||||
}
|
||||
|
||||
func swapTwoDoubles(inout a: Double, inout b: Double) {
|
||||
func swapTwoDoubles(inout a: Double, inout _ b: Double) {
|
||||
let temporaryA = a
|
||||
a = b
|
||||
b = temporaryA
|
||||
}
|
||||
```
|
||||
|
||||
你可能注意到 `swapTwoInts`、 `swapTwoStrings`和`swapTwoDoubles`函数功能都是相同的,唯一不同之处就在于传入的变量类型不同,分别是`Int`、`String`和`Double`。
|
||||
你可能注意到 `swapTwoInts`、 `swapTwoStrings`和`swapTwoDoubles(_:_:)`函数功能都是相同的,唯一不同之处就在于传入的变量类型不同,分别是`Int`、`String`和`Double`。
|
||||
|
||||
但实际应用中通常需要一个用处更强大并且尽可能的考虑到更多的灵活性单个函数,可以用来交换两个任何类型值,很幸运的是,泛型代码帮你解决了这种问题。(一个这种泛型函数后面已经定义好了。)
|
||||
|
||||
@ -73,29 +74,29 @@ func swapTwoDoubles(inout a: Double, inout b: Double) {
|
||||
<a name="generic_functions"></a>
|
||||
## 泛型函数
|
||||
|
||||
`泛型函数`可以工作于任何类型,这里是一个上面`swapTwoInts`函数的泛型版本,用于交换两个值:
|
||||
`泛型函数`可以工作于任何类型,这里是一个上面`swapTwoInts(_:_:)`函数的泛型版本,用于交换两个值:
|
||||
|
||||
```swift
|
||||
func swapTwoValues<T>(inout a: T, inout b: T) {
|
||||
func swapTwoValues<T>(inout a: T, inout _ b: T) {
|
||||
let temporaryA = a
|
||||
a = b
|
||||
b = temporaryA
|
||||
}
|
||||
```
|
||||
|
||||
`swapTwoValues`函数主体和`swapTwoInts`函数是一样的,它只在第一行稍微有那么一点点不同于`swapTwoInts`,如下所示:
|
||||
`swapTwoValues(_:_:)`函数主体和`swapTwoInts(_:_:)`函数是一样的,它只在第一行稍微有那么一点点不同于`swapTwoInts`,如下所示:
|
||||
|
||||
```swift
|
||||
func swapTwoInts(inout a: Int, inout b: Int)
|
||||
func swapTwoValues<T>(inout a: T, inout b: T)
|
||||
func swapTwoInts(inout a: Int, inout _ b: Int)
|
||||
func swapTwoValues<T>(inout a: T, inout _ b: T)
|
||||
```
|
||||
|
||||
|
||||
这个函数的泛型版本使用了占位类型名字(通常此情况下用字母`T`来表示)来代替实际类型名(如`Int`、`String`或`Double`)。占位类型名没有提示`T`必须是什么类型,但是它提示了`a`和`b`必须是同一类型`T`,而不管`T`表示什么类型。只有`swapTwoValues`函数在每次调用时所传入的实际类型才能决定`T`所代表的类型。
|
||||
这个函数的泛型版本使用了占位类型名字(通常此情况下用字母`T`来表示)来代替实际类型名(如`Int`、`String`或`Double`)。占位类型名没有提示`T`必须是什么类型,但是它提示了`a`和`b`必须是同一类型`T`,而不管`T`表示什么类型。只有`swapTwoValues(_:_:)`函数在每次调用时所传入的实际类型才能决定`T`所代表的类型。
|
||||
|
||||
另外一个不同之处在于这个泛型函数名后面跟着的占位类型名字(T)是用尖括号括起来的(`<T>`)。这个尖括号告诉 Swift 那个`T`是`swapTwoValues`函数所定义的一个类型。因为`T`是一个占位命名类型,Swift 不会去查找命名为T的实际类型。
|
||||
另外一个不同之处在于这个泛型函数名后面跟着的占位类型名字(T)是用尖括号括起来的(`<T>`)。这个尖括号告诉 Swift 那个`T`是`swapTwoValues(_:_:)`函数所定义的一个类型。因为`T`是一个占位命名类型,Swift 不会去查找命名为T的实际类型。
|
||||
|
||||
`swapTwoValues`函数除了要求传入的两个任何类型值是同一类型外,也可以作为`swapTwoInts`函数被调用。每次`swapTwoValues`被调用,T所代表的类型值都会传给函数。
|
||||
`swapTwoValues(_:_:)`函数除了要求传入的两个任何类型值是同一类型外,也可以作为`swapTwoInts`函数被调用。每次`swapTwoValues`被调用,T所代表的类型值都会传给函数。
|
||||
|
||||
在下面的两个例子中,`T`分别代表`Int`和`String`:
|
||||
|
||||
@ -103,26 +104,26 @@ func swapTwoValues<T>(inout a: T, inout b: T)
|
||||
var someInt = 3
|
||||
var anotherInt = 107
|
||||
swapTwoValues(&someInt, &anotherInt)
|
||||
// someInt is now 107, and anotherInt is now 3
|
||||
// someInt 现在等于 107, anotherInt 现在等于 3
|
||||
```
|
||||
|
||||
```swift
|
||||
var someString = "hello"
|
||||
var anotherString = "world"
|
||||
swapTwoValues(&someString, &anotherString)
|
||||
// someString is now "world", and anotherString is now "hello"
|
||||
// someString 现在等于 "world", anotherString 现在等于 "hello"
|
||||
```
|
||||
|
||||
|
||||
>注意
|
||||
上面定义的函数`swapTwoValues`是受`swap`函数启发而实现的。`swap`函数存在于 Swift 标准库,并可以在其它类中任意使用。如果你在自己代码中需要类似`swapTwoValues`函数的功能,你可以使用已存在的交换函数`swap`函数。
|
||||
上面定义的函数`swapTwoValues(_:_:)`是受`swap`函数启发而实现的。`swap`函数存在于 Swift 标准库,并可以在其它类中任意使用。如果你在自己代码中需要类似`swapTwoValues(_:_:)`函数的功能,你可以使用已存在的交换函数`swap(_:_:)`函数。
|
||||
|
||||
<a name="type_parameters"></a>
|
||||
## 类型参数
|
||||
|
||||
在上面的`swapTwoValues`例子中,占位类型`T`是一种类型参数的示例。类型参数指定并命名为一个占位类型,并且紧随在函数名后面,使用一对尖括号括起来(如`<T>`)。
|
||||
|
||||
一旦一个类型参数被指定,那么其可以被使用来定义一个函数的参数类型(如`swapTwoValues`函数中的参数`a`和`b`),或作为一个函数返回类型,或用作函数主体中的注释类型。在这种情况下,被类型参数所代表的占位类型不管函数任何时候被调用,都会被实际类型所替换(在上面`swapTwoValues`例子中,当函数第一次被调用时,`T`被`Int`替换,第二次调用时,被`String`替换。)。
|
||||
一旦一个类型参数被指定,那么其可以被使用来定义一个函数的参数类型(如`swapTwoValues(_:_:)`函数中的参数`a`和`b`),或作为一个函数返回类型,或用作函数主体中的注释类型。在这种情况下,被类型参数所代表的占位类型不管函数任何时候被调用,都会被实际类型所替换(在上面`swapTwoValues`例子中,当函数第一次被调用时,`T`被`Int`替换,第二次调用时,被`String`替换。)。
|
||||
|
||||
你可支持多个类型参数,命名在尖括号中,用逗号分开。
|
||||
|
||||
@ -131,10 +132,10 @@ swapTwoValues(&someString, &anotherString)
|
||||
|
||||
在简单的情况下,泛型函数或泛型类型需要指定一个占位类型(如上面的`swapTwoValues`泛型函数,或一个存储单一类型的泛型集,如数组),通常用一单个字母`T`来命名类型参数。不过,你可以使用任何有效的标识符来作为类型参数名。
|
||||
|
||||
如果你使用多个参数定义更复杂的泛型函数或泛型类型,那么使用更多的描述类型参数是非常有用的。例如,Swift 字典(Dictionary)类型有两个类型参数,一个是键,另外一个是值。如果你自己写字典,你或许会定义这两个类型参数为`KeyType`和`ValueType`,用来记住它们在你的泛型代码中的作用。
|
||||
如果你使用多个参数定义更复杂的泛型函数或泛型类型,那么使用更多的描述类型参数是非常有用的。例如,Swift 字典(Dictionary)类型有两个类型参数,一个是键,另外一个是值。如果你自己写字典,你或许会定义这两个类型参数为`Key`和`Value`,用来记住它们在你的泛型代码中的作用。
|
||||
|
||||
>注意
|
||||
请始终使用大写字母开头的驼峰式命名法(例如`T`和`KeyType`)来给类型参数命名,以表明它们是类型的占位符,而非类型值。
|
||||
请始终使用大写字母开头的驼峰式命名法(例如`T`和`Key`)来给类型参数命名,以表明它们是类型的占位符,而非类型值。
|
||||
|
||||
<a name="generic_types"></a>
|
||||
## 泛型类型
|
||||
@ -145,7 +146,7 @@ swapTwoValues(&someString, &anotherString)
|
||||
这部分向你展示如何写一个泛型集类型--`Stack`(栈)。一个栈是一系列值域的集合,和`Array`(数组)类似,但其是一个比 Swift 的`Array`类型更多限制的集合。一个数组可以允许其里面任何位置的插入/删除操作,而栈,只允许在集合的末端添加新的项(如同*push*一个新值进栈)。同样的一个栈也只能从末端移除项(如同*pop*一个值出栈)。
|
||||
|
||||
>注意
|
||||
栈的概念已被`UINavigationController`类使用来模拟试图控制器的导航结构。你通过调用`UINavigationController`的`pushViewController:animated:`方法来为导航栈添加(add)新的试图控制器;而通过`popViewControllerAnimated:`的方法来从导航栈中移除(pop)某个试图控制器。每当你需要一个严格的`后进先出`方式来管理集合,堆栈都是最实用的模型。
|
||||
栈的概念已被`UINavigationController`类使用来模拟试图控制器的导航结构。你通过调用`UINavigationController`的`pushViewController(_:animated:)`方法来为导航栈添加(add)新的试图控制器;而通过`popViewControllerAnimated(_:)`的方法来从导航栈中移除(pop)某个试图控制器。每当你需要一个严格的`后进先出`方式来管理集合,堆栈都是最实用的模型。
|
||||
|
||||
下图展示了一个栈的压栈(push)/出栈(pop)的行为:
|
||||
|
||||
@ -161,7 +162,7 @@ swapTwoValues(&someString, &anotherString)
|
||||
|
||||
```swift
|
||||
struct IntStack {
|
||||
var items = Int[]()
|
||||
var items = [Int]()
|
||||
mutating func push(item: Int) {
|
||||
items.append(item)
|
||||
}
|
||||
@ -196,10 +197,12 @@ struct Stack<T> {
|
||||
`T`定义了一个名为“某种类型T”的节点提供给后来用。这种将来类型可以在结构体的定义里任何地方表示为“T”。在这种情况下,`T`在如下三个地方被用作节点:
|
||||
|
||||
- 创建一个名为`items`的属性,使用空的T类型值数组对其进行初始化;
|
||||
- 指定一个包含一个参数名为`item`的`push`方法,该参数必须是T类型;
|
||||
- 指定一个包含一个参数名为`item`的`push(_:)`方法,该参数必须是T类型;
|
||||
- 指定一个`pop`方法的返回值,该返回值将是一个T类型值。
|
||||
|
||||
当创建一个新单例并初始化时, 通过用一对紧随在类型名后的尖括号里写出实际指定栈用到类型,创建一个`Stack`实例,同创建`Array`和`Dictionary`一样:
|
||||
由于`Stack`是泛型类型,所以在 Swift 中其可以用来创建任何有效类型的栈,这种方式如同`Array`和`Dictionary`。
|
||||
|
||||
你可以通过在尖括号里写出栈中需要存储的数据类型来创建并初始化一个`Stack`实例。比如,要创建一个`strings`的栈,你可以写成`Stack<String>()`:
|
||||
|
||||
```swift
|
||||
var stackOfStrings = Stack<String>()
|
||||
@ -218,18 +221,44 @@ stackOfStrings.push("cuatro")
|
||||
|
||||
```swift
|
||||
let fromTheTop = stackOfStrings.pop()
|
||||
// fromTheTop is equal to "cuatro", and the stack now contains 3 strings
|
||||
// fromTheTop 等于 "cuatro", 现在栈中还有3个string
|
||||
```
|
||||
|
||||
下图展示了如何从栈中pop一个值的过程:
|
||||

|
||||
|
||||
由于`Stack`是泛型类型,所以在 Swift 中其可以用来创建任何有效类型的栈,这种方式如同`Array`和`Dictionary`。
|
||||
<a name="extending_a_generic_type"></a>
|
||||
## 扩展一个泛型类型
|
||||
|
||||
当你扩展一个泛型类型的时候,你并不需要在扩展的定义中提供类型参数列表。更加方便的是,原始类型定义中声明的类型参数列表在扩展里是可以使用的,并且这些来自原始类型中的参数名称会被用作原始定义中类型参数的引用。
|
||||
|
||||
下面的例子扩展了泛型`Stack`类型,为其添加了一个名为`topItem`的只读计算属性,它将会返回当前栈顶端的元素而不会将其从栈中移除。
|
||||
|
||||
```swift
|
||||
extension Stack {
|
||||
var topItem: T? {
|
||||
return items.isEmpty ? nil : items[items.count - 1]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
`topItem`属性会返回一个`T`类型的可选值。当栈为空的时候,`topItem`将会返回`nil`;当栈不为空的时候,`topItem`会返回`items`数组中的最后一个元素。
|
||||
|
||||
注意这里的扩展并没有定义一个类型参数列表。相反的,`Stack`类型已有的类型参数名称,`T`,被用在扩展中当做`topItem`计算属性的可选类型。
|
||||
|
||||
`topItem`计算属性现在可以被用来返回任意`Stack`实例的顶端元素而无需移除它:
|
||||
|
||||
```swift
|
||||
if let topItem = stackOfStrings.topItem {
|
||||
print("The top item on the stack is \(topItem).")
|
||||
}
|
||||
// 输出 "The top item on the stack is tres."
|
||||
```
|
||||
|
||||
<a name="type_constraints"></a>
|
||||
##类型约束
|
||||
|
||||
`swapTwoValues`函数和`Stack`类型可以作用于任何类型,不过,有的时候对使用在泛型函数和泛型类型上的类型强制约束为某种特定类型是非常有用的。类型约束指定了一个必须继承自指定类的类型参数,或者遵循一个特定的协议或协议构成。
|
||||
`swapTwoValues(_:_:)`函数和`Stack`类型可以作用于任何类型,不过,有的时候对使用在泛型函数和泛型类型上的类型强制约束为某种特定类型是非常有用的。类型约束指定了一个必须继承自指定类的类型参数,或者遵循一个特定的协议或协议构成。
|
||||
|
||||
例如,Swift 的`Dictionary`类型对作用于其键的类型做了些限制。在[字典](../chapter2/04_Collection_Types.html)的描述中,字典的键类型必须是*可哈希*,也就是说,必须有一种方法可以使其被唯一的表示。`Dictionary`之所以需要其键是可哈希是为了以便于其检查其是否已经包含某个特定键的值。如无此需求,`Dictionary`既不会告诉是否插入或者替换了某个特定键的值,也不能查找到已经存储在字典里面的给定键值。
|
||||
|
||||
@ -243,7 +272,7 @@ let fromTheTop = stackOfStrings.pop()
|
||||
|
||||
```swift
|
||||
func someFunction<T: SomeClass, U: SomeProtocol>(someT: T, someU: U) {
|
||||
// function body goes here
|
||||
// 这里是函数主体
|
||||
}
|
||||
```
|
||||
|
||||
@ -251,11 +280,11 @@ func someFunction<T: SomeClass, U: SomeProtocol>(someT: T, someU: U) {
|
||||
|
||||
### 类型约束行为
|
||||
|
||||
这里有个名为`findStringIndex`的非泛型函数,该函数功能是去查找包含一给定`String`值的数组。若查找到匹配的字符串,`findStringIndex`函数返回该字符串在数组中的索引值(`Int`),反之则返回`nil`:
|
||||
这里有个名为`findStringIndex`的非泛型函数,该函数功能是去查找包含一给定`String`值的数组。若查找到匹配的字符串,`findStringIndex(_:_:)`函数返回该字符串在数组中的索引值(`Int`),反之则返回`nil`:
|
||||
|
||||
```swift
|
||||
func findStringIndex(array: [String], valueToFind: String) -> Int? {
|
||||
for (index, value) in enumerate(array) {
|
||||
func findStringIndex(array: [String], _ valueToFind: String) -> Int? {
|
||||
for (index, value) in array.enumerate() {
|
||||
if value == valueToFind {
|
||||
return index
|
||||
}
|
||||
@ -265,12 +294,12 @@ func findStringIndex(array: [String], valueToFind: String) -> Int? {
|
||||
```
|
||||
|
||||
|
||||
`findStringIndex`函数可以作用于查找一字符串数组中的某个字符串:
|
||||
`findStringIndex(_:_:)`函数可以作用于查找一字符串数组中的某个字符串:
|
||||
|
||||
```swift
|
||||
let strings = ["cat", "dog", "llama", "parakeet", "terrapin"]
|
||||
if let foundIndex = findStringIndex(strings, "llama") {
|
||||
println("The index of llama is \(foundIndex)")
|
||||
print("The index of llama is \(foundIndex)")
|
||||
}
|
||||
// 输出 "The index of llama is 2"
|
||||
```
|
||||
@ -280,8 +309,8 @@ if let foundIndex = findStringIndex(strings, "llama") {
|
||||
这里展示如何写一个你或许期望的`findStringIndex`的泛型版本`findIndex`。请注意这个函数仍然返回`Int`,是不是有点迷惑呢,而不是泛型类型?那是因为函数返回的是一个可选的索引数,而不是从数组中得到的一个可选值。需要提醒的是,这个函数不会编译,原因在例子后面会说明:
|
||||
|
||||
```swift
|
||||
func findIndex<T>(array: [T], valueToFind: T) -> Int? {
|
||||
for (index, value) in enumerate(array) {
|
||||
func findIndex<T>(array: [T], _ valueToFind: T) -> Int? {
|
||||
for (index, value) in array.enumerate() {
|
||||
if value == valueToFind {
|
||||
return index
|
||||
}
|
||||
@ -294,11 +323,11 @@ func findIndex<T>(array: [T], valueToFind: T) -> Int? {
|
||||
|
||||
不过,所有的这些并不会让我们无从下手。Swift 标准库中定义了一个`Equatable`协议,该协议要求任何遵循的类型实现等式符(==)和不等符(!=)对任何两个该类型进行比较。所有的 Swift 标准类型自动支持`Equatable`协议。
|
||||
|
||||
任何`Equatable`类型都可以安全的使用在`findIndex`函数中,因为其保证支持等式操作。为了说明这个事实,当你定义一个函数时,你可以写一个`Equatable`类型约束作为类型参数定义的一部分:
|
||||
任何`Equatable`类型都可以安全的使用在`findIndex(_:_:)`函数中,因为其保证支持等式操作。为了说明这个事实,当你定义一个函数时,你可以写一个`Equatable`类型约束作为类型参数定义的一部分:
|
||||
|
||||
```swift
|
||||
func findIndex<T: Equatable>(array: T[], valueToFind: T) -> Int? {
|
||||
for (index, value) in enumerate(array) {
|
||||
func findIndex<T: Equatable>(array: [T], _ valueToFind: T) -> Int? {
|
||||
for (index, value) in array.enumerate() {
|
||||
if value == valueToFind {
|
||||
return index
|
||||
}
|
||||
@ -310,7 +339,7 @@ func findIndex<T: Equatable>(array: T[], valueToFind: T) -> Int? {
|
||||
|
||||
`findIndex`中这个单个类型参数写做:`T: Equatable`,也就意味着“任何T类型都遵循`Equatable`协议”。
|
||||
|
||||
`findIndex`函数现在则可以成功的编译过,并且作用于任何遵循`Equatable`的类型,如`Double`或`String`:
|
||||
`findIndex(_:_:)`函数现在则可以成功的编译过,并且作用于任何遵循`Equatable`的类型,如`Double`或`String`:
|
||||
|
||||
```swift
|
||||
let doubleIndex = findIndex([3.14159, 0.1, 0.25], 9.3)
|
||||
@ -326,7 +355,7 @@ let stringIndex = findIndex(["Mike", "Malcolm", "Andrea"], "Andrea")
|
||||
|
||||
### 关联类型行为
|
||||
|
||||
这里是一个`Container`协议的例子,定义了一个ItemType关联类型:
|
||||
这里是一个`Container`协议的例子,定义了一个`ItemType`关联类型:
|
||||
|
||||
```swift
|
||||
protocol Container {
|
||||
@ -339,19 +368,19 @@ protocol Container {
|
||||
|
||||
`Container`协议定义了三个任何容器必须支持的兼容要求:
|
||||
|
||||
- 必须可以通过`append`方法添加一个新item到容器里;
|
||||
- 必须可以通过使用`count`属性获取容器里items的数量,并返回一个`Int`值;
|
||||
- 必须可以通过容器的`Int`索引值下标可以检索到每一个item。
|
||||
- 必须可以通过`append(_:)`方法添加一个新元素到容器里;
|
||||
- 必须可以通过使用`count`属性获取容器里元素的数量,并返回一个`Int`值;
|
||||
- 必须可以通过容器的`Int`索引值下标可以检索到每一个元素。
|
||||
|
||||
这个协议没有指定容器里item是如何存储的或何种类型是允许的。这个协议只指定三个任何遵循`Container`类型所必须支持的功能点。一个遵循的类型在满足这三个条件的情况下也可以提供其他额外的功能。
|
||||
这个协议没有指定容器里的元素是如何存储的或何种类型是允许的。这个协议只指定三个任何遵循`Container`类型所必须支持的功能点。一个遵循的类型在满足这三个条件的情况下也可以提供其他额外的功能。
|
||||
|
||||
任何遵循`Container`协议的类型必须指定存储在其里面的值类型,必须保证只有正确类型的items可以加进容器里,必须明确可以通过其下标返回item类型。
|
||||
任何遵循`Container`协议的类型必须指定存储在其里面的值类型,必须保证只有正确类型的元素可以加进容器里,必须明确可以通过其下标返回元素类型。
|
||||
|
||||
为了定义这三个条件,`Container`协议需要一个方法指定容器里的元素将会保留,而不需要知道特定容器的类型。`Container`协议需要指定任何通过`append`方法添加到容器里的值和容器里元素是相同类型,并且通过容器下标返回的容器元素类型的值的类型是相同类型。
|
||||
为了定义这三个条件,`Container`协议需要一个方法指定容器里的元素将会保留,而不需要知道特定容器的类型。`Container`协议需要指定任何通过`append(_:)`方法添加到容器里的值和容器里元素是相同类型,并且通过容器下标返回的容器元素类型的值的类型是相同类型。
|
||||
|
||||
为了达到此目的,`Container`协议声明了一个ItemType的关联类型,写作`typealias ItemType`。这个协议不会定义`ItemType`是什么的别名,这个信息将由任何遵循协议的类型来提供。尽管如此,`ItemType`别名提供了一种识别Container中Items类型的方法,并且用于`append`方法和`subscript`方法的类型定义,以便保证任何`Container`期望的行为能够被执行。
|
||||
为了达到此目的,`Container`协议声明了一个`ItemType`的关联类型,写作`typealias ItemType`。这个协议不会定义`ItemType`是什么的别名,这个信息将由任何遵循协议的类型来提供。尽管如此,`ItemType`别名提供了一种识别`Container`中元素类型的方法,并且用于`append(_:)`方法和`subscript`方法的类型定义,以便保证任何`Container`期望的行为能够被执行。
|
||||
|
||||
这里是一个早前IntStack类型的非泛型版本,遵循Container协议:
|
||||
这里是一个早前`IntStack`类型的非泛型版本,遵循`Container`协议:
|
||||
|
||||
```swift
|
||||
struct IntStack: Container {
|
||||
@ -380,9 +409,9 @@ struct IntStack: Container {
|
||||
|
||||
`IntStack`类型实现了`Container`协议的所有三个要求,在`IntStack`类型的每个包含部分的功能都满足这些要求。
|
||||
|
||||
此外,`IntStack`指定了`Container`的实现,适用的ItemType被用作`Int`类型。对于这个`Container`协议实现而言,定义 `typealias ItemType = Int`,将抽象的`ItemType`类型转换为具体的`Int`类型。
|
||||
此外,`IntStack`指定了`Container`的实现,适用的`ItemType`被用作`Int`类型。对于这个`Container`协议实现而言,定义 `typealias ItemType = Int`,将抽象的`ItemType`类型转换为具体的`Int`类型。
|
||||
|
||||
感谢Swift类型参考,你不用在`IntStack`定义部分声明一个具体的`Int`的`ItemType`。由于`IntStack`遵循`Container`协议的所有要求,只要通过简单的查找`append`方法的item参数类型和下标返回的类型,Swift就可以推断出合适的`ItemType`来使用。确实,如果上面的代码中你删除了 `typealias ItemType = Int`这一行,一切仍旧可以工作,因为它清楚的知道ItemType使用的是何种类型。
|
||||
感谢Swift类型参考,你不用在`IntStack`定义部分声明一个具体的`Int`的`ItemType`。由于`IntStack`遵循`Container`协议的所有要求,只要通过简单的查找`append(_:)`方法的`item`参数类型和下标返回的类型,Swift就可以推断出合适的`ItemType`来使用。确实,如果上面的代码中你删除了 `typealias ItemType = Int`这一行,一切仍旧可以工作,因为它清楚的知道`ItemType`使用的是何种类型。
|
||||
|
||||
你也可以生成遵循`Container`协议的泛型`Stack`类型:
|
||||
|
||||
@ -409,20 +438,20 @@ struct Stack<T>: Container {
|
||||
}
|
||||
```
|
||||
|
||||
这个时候,占位类型参数`T`被用作`append`方法的item参数和下标的返回类型。Swift 因此可以推断出被用作这个特定容器的`ItemType`的`T`的合适类型。
|
||||
这个时候,占位类型参数`T`被用作`append(_:)`方法的`item`参数和下标的返回类型。Swift 因此可以推断出被用作这个特定容器的`ItemType`的`T`的合适类型。
|
||||
|
||||
|
||||
### 扩展一个存在的类型为一指定关联类型
|
||||
|
||||
在[使用扩展来添加协议兼容性](../chapter2/21_Protocols.html)中有描述扩展一个存在的类型添加遵循一个协议。这个类型包含一个关联类型的协议。
|
||||
|
||||
Swift的`Array`已经提供`append`方法,一个`count`属性和通过下标来查找一个自己的元素。这三个功能都达到`Container`协议的要求。也就意味着你可以扩展`Array`去遵循`Container`协议,只要通过简单声明`Array`适用于该协议而已。如何实践这样一个空扩展,在[使用扩展来声明协议的采纳](../chapter2/21_Protocols.html)中有描述这样一个实现一个空扩展的行为:
|
||||
Swift的`Array`已经提供`append(_:)`方法,一个`count`属性和通过下标来查找一个自己的元素。这三个功能都达到`Container`协议的要求。也就意味着你可以扩展`Array`去遵循`Container`协议,只要通过简单声明`Array`适用于该协议而已。如何实践这样一个空扩展,在[使用扩展来声明协议的采纳](../chapter2/21_Protocols.html)中有描述这样一个实现一个空扩展的行为:
|
||||
|
||||
```swift
|
||||
extension Array: Container {}
|
||||
```
|
||||
|
||||
如同上面的泛型`Stack`类型一样,`Array的append`方法和下标保证`Swift`可以推断出`ItemType`所使用的适用的类型。定义了这个扩展后,你可以将任何`Array`当作`Container`来使用。
|
||||
如同上面的泛型`Stack`类型一样,`Array`的`append(_:)`方法和下标保证`Swift`可以推断出`ItemType`所使用的适用的类型。定义了这个扩展后,你可以将任何`Array`当作`Container`来使用。
|
||||
|
||||
<a name="where_clauses"></a>
|
||||
## Where 语句
|
||||
@ -480,15 +509,15 @@ func allItemsMatch<
|
||||
|
||||
第三个和第四个要求结合起来的意思是`anotherContainer`中的元素也可以通过 `!=` 操作来检查,因为它们在`someContainer`中元素确实是相同的类型。
|
||||
|
||||
这些要求能够使`allItemsMatch`函数比较两个容器,即便它们是不同的容器类型。
|
||||
这些要求能够使`allItemsMatch(_:_:)`函数比较两个容器,即便它们是不同的容器类型。
|
||||
|
||||
`allItemsMatch`首先检查两个容器是否拥有同样数目的items,如果它们的元素数目不同,没有办法进行匹配,函数就会`false`。
|
||||
`allItemsMatch(_:_:)`首先检查两个容器是否拥有同样数目的items,如果它们的元素数目不同,没有办法进行匹配,函数就会`false`。
|
||||
|
||||
检查完之后,函数通过`for-in`循环和半闭区间操作(..)来迭代`someContainer`中的所有元素。对于每个元素,函数检查是否`someContainer`中的元素不等于对应的`anotherContainer`中的元素,如果这两个元素不等,则这两个容器不匹配,返回`false`。
|
||||
检查完之后,函数通过`for-in`循环和半闭区间操作(`..<`)来迭代`someContainer`中的所有元素。对于每个元素,函数检查是否`someContainer`中的元素不等于对应的`anotherContainer`中的元素,如果这两个元素不等,则这两个容器不匹配,返回`false`。
|
||||
|
||||
如果循环体结束后未发现没有任何的不匹配,那表明两个容器匹配,函数返回`true`。
|
||||
|
||||
这里演示了allItemsMatch函数运算的过程:
|
||||
这里演示了`allItemsMatch(_:_:)`函数运算的过程:
|
||||
|
||||
```swift
|
||||
var stackOfStrings = Stack<String>()
|
||||
@ -499,14 +528,14 @@ stackOfStrings.push("tres")
|
||||
var arrayOfStrings = ["uno", "dos", "tres"]
|
||||
|
||||
if allItemsMatch(stackOfStrings, arrayOfStrings) {
|
||||
println("All items match.")
|
||||
print("All items match.")
|
||||
} else {
|
||||
println("Not all items match.")
|
||||
print("Not all items match.")
|
||||
}
|
||||
// 输出 "All items match."
|
||||
```
|
||||
|
||||
上面的例子创建一个`Stack`单例来存储`String`,然后压了三个字符串进栈。这个例子也创建了一个`Array`单例,并初始化包含三个同栈里一样的原始字符串。即便栈和数组是不同的类型,但它们都遵循`Container`协议,而且它们都包含同样的类型值。因此你可以调用`allItemsMatch`函数,用这两个容器作为它的参数。在上面的例子中,`allItemsMatch`函数正确的显示了所有的这两个容器的`items`匹配。
|
||||
上面的例子创建一个`Stack`单例来存储`String`,然后压了三个字符串进栈。这个例子也创建了一个`Array`单例,并初始化包含三个同栈里一样的原始字符串。即便栈和数组是不同的类型,但它们都遵循`Container`协议,而且它们都包含同样的类型值。因此你可以调用`allItemsMatch(_:_:)`函数,用这两个容器作为它的参数。在上面的例子中,`allItemsMatch(_:_:)`函数正确的显示了这两个容器的所有元素都是相互匹配的。
|
||||
|
||||
[1]: ../chapter2/06_Functions.html
|
||||
[2]: https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Art/stackPushPop_2x.png
|
||||
|
||||
@ -12,6 +12,7 @@
|
||||
- [默认访问级别](#default_access_levels)
|
||||
- [单目标应用程序的访问级别](#access_levels_for_single-target_apps)
|
||||
- [Framework的访问级别](#access_levels_for_frameworks)
|
||||
- [单元测试目标的访问级别](#access_levels_for_unit_test_targets)
|
||||
- [访问控制语法](#access_control_syntax)
|
||||
- [自定义类型](#custom_types)
|
||||
- [元组类型](#tuple_types)
|
||||
@ -33,45 +34,47 @@
|
||||
- [泛型](#generics)
|
||||
- [类型别名](#type_aliases)
|
||||
|
||||
访问控制可以限定你在源文件或模块中访问代码的级别,也就是说可以控制哪些代码你可以访问,哪些代码你不能访问。这个特性可以让我们隐藏功能实现的一些细节,并且可以明确的指定我们提供给其他人的接口中哪些部分是他们可以使用的,哪些是他们看不到的。
|
||||
*访问控制*可以限定其他源文件或模块中代码对你代码的访问级别。这个特性可以让我们隐藏功能实现的一些细节,并且可以明确的申明我们提供给其他人的接口中哪些部分是他们可以访问和使用的。
|
||||
|
||||
你可以明确的给类、结构体、枚举、设置访问级别,也可以给属性、函数、初始化方法、基本类型、下标索引等设置访问级别。协议也可以被限定在一定的范围内使用,包括协议里的全局常量、变量和函数。
|
||||
你可以明确地给单个类型(类、结构体、枚举)设置访问级别,也可以给这些类型的属性、函数、初始化方法、基本类型、下标索引等设置访问级别。协议也可以被限定在一定的范围内使用,包括协议里的全局常量、变量和函数。
|
||||
|
||||
在提供了不同访问级别的同时,Swift 并没有规定我们要在任何时候都要在代码中明确指定访问级别。其实,如果我们作为独立开发者在开发我们自己的 app,而不是在开发一些`Framework`的时候,我们完全可以不用明确的指定代码的访问级别。
|
||||
在提供了不同访问级别的同时,Swift还为某些典型场景提供了默认的访问级别,这样就不需要我们在每段代码中都申明显式访问级别。其实,如果只是开发一个单目标应用程序,我们完全可以不用申明代码的显式访问级别。
|
||||
|
||||
> 注意:为方便起见,在代码中可以设置访问级别的它们(属性、基本类型、函数等)在下面的章节中我们称之为“实体”。
|
||||
> 注意:简单起见,代码中可以设置访问级别的特性(属性、基本类型、函数等),在下面的章节中我们会以“实体”代替。
|
||||
|
||||
<a name="modules_and_source_files"></a>
|
||||
## 模块和源文件
|
||||
Swift 中的访问控制模型基于模块和源文件这两个概念。
|
||||
|
||||
模块指的是`Framework`或`App bundle`。在 Swift 中,可以用`import`关键字引入自己的工程。
|
||||
*模块*指的是以独立单元构建和发布的`Framework`或`Application`。在Swift 中的一个模块可以使用`import`关键字引入另外一个模块。
|
||||
|
||||
在 Swift 中,`Framework`或`App bundle`被作为模块处理。如果你是为了实现某个通用的功能,或者是为了封装一些常用方法而将代码打包成`Framework`,这个`Framework`在 Swift 中就被称为模块。不论它被引入到某个 App 工程或者其他的`Framework`,它里面的一切(属性、函数等)都属于这个模块。
|
||||
在 Swift 中,Xcode的每个构建目标(比如`Framework`或`app bundle`)都被当作模块处理。如果你是为了实现某个通用的功能,或者是为了封装一些常用方法而将代码打包成独立的`Framework`,这个`Framework`在 Swift 中就被称为模块。当它被引入到某个 app 工程或者另外一个`Framework`时,它里面的一切(属性、函数等)仍然属于这个独立的模块。
|
||||
|
||||
源文件指的是 Swift 中的`Swift File`,就是编写 Swift 代码的文件,它通常属于一个模块。通常一个源文件包含一个`类`,在`类`中又包含`函数`、`属性`等类型。
|
||||
*源文件*指的是 Swift 中的`Swift File`,就是编写 Swift 源代码的文件,它通常属于一个模块。尽管一般我们将不同的`类` 分别定义在不同的源文件中,但是同一个源文件可以包含多个`类`和`函数` 的定义。
|
||||
|
||||
<a name="access_levels"></a>
|
||||
## 访问级别
|
||||
Swift 提供了三种不同的访问级别。这些访问级别相对于源文件中定义的实体,同时也相对于这些源文件所属的模块。
|
||||
Swift 为代码中的实体提供了三种不同的访问级别。这些访问级别不仅与源文件中定义的实体相关,同时也与源文件所属的模块相关。
|
||||
|
||||
- `Public`:可以访问自己模块或应用中源文件里的任何实体,别人也可以访问引入该模块中源文件里的所有实体。通常情况下,某个接口或`Framework`是可以被任何人使用时,你可以将其设置为`public`级别。
|
||||
- `Internal`:可以访问自己模块或应用中源文件里的任何实体,但是别人不能访问该模块中源文件里的实体。通常情况下,某个接口或`Framework`作为内部结构使用时,你可以将其设置为`internal`级别。
|
||||
- `Private`:只能在当前源文件中使用的实体,称为私有实体。使用`private`级别,可以用作隐藏某些功能的实现细节。
|
||||
- `public`:可以访问自己模块中源文件里的任何实体,别人也可以通过引入该模块来访问源文件里的所有实体。通常情况下,`Framework` 中的某个接口是可以被任何人使用时,你可以将其设置为`public`级别。
|
||||
- `internal`:可以访问自己模块中源文件里的任何实体,但是别人不能访问该模块中源文件里的实体。通常情况下,某个接口或`Framework`作为内部结构使用时,你可以将其设置为`internal`级别。
|
||||
- `private`:只能在当前源文件中使用的实体,称为私有实体。使用`private`级别,可以用作隐藏某些功能的实现细节。
|
||||
|
||||
`Public`为最高级访问级别,`Private`为最低级访问级别。
|
||||
`public`为最高级访问级别,`private`为最低级访问级别。
|
||||
|
||||
> 注意:Swift中的`private`访问和其他语言中的`private`访问不太一样,它的范围限于整个源文件,而不是声明。这就意味着,一个`类` 可以访问定义该`类` 的源文件中定义的所有`private`实体,但是如果一个`类` 的扩展是定义在独立的源文件中,那么就不能访问这个`类` 的`private`成员。
|
||||
|
||||
<a name="guiding_principle_of_access_levels"></a>
|
||||
### 访问级别的使用原则
|
||||
在 Swift 中,访问级别有如下使用原则:访问级别统一性。
|
||||
Swift 中的访问级别遵循一个使用原则:访问级别统一性。
|
||||
比如说:
|
||||
|
||||
- 一个`public`访问级别的变量,不能将它的类型定义为`internal`和`private`的类型。因为变量可以被任何人访问,但是定义它的类型不可以,所以这样就会出现错误。
|
||||
- 函数的访问级别不能高于它的参数、返回类型的访问级别。因为如果函数定义为`public`而参数或者返回类型定义为`internal`或`private`,就会出现函数可以被任何人访问,但是它的参数和返回类型不可以,同样会出现错误。
|
||||
- 一个`public`访问级别的变量,不能将它的类型定义为`internal`和`private`。因为变量可以被任何人访问,但是定义它的类型不可以,所以这样就会出现错误。
|
||||
- 函数的访问级别不能高于它的参数、返回类型的访问级别。因为如果函数定义为`public`而参数或者返回类型定义为`internal`或`private`,就会出现函数可以被任何人访问,但是它的参数和返回类型确不可以,同样会出现错误。
|
||||
|
||||
<a name="default_access_levels"></a>
|
||||
### 默认访问级别
|
||||
代码中的所有实体,如果你不明确的定义其访问级别,那么它们默认为`internal`级别。在大多数情况下,我们不需要明确的设置实体的访问级别,因为我们大多数时候都是在开发一个 App bundle。
|
||||
如果你不为代码中的所有实体定义显式访问级别,那么它们默认为`internal`级别。在大多数情况下,我们不需要设置实体的显式访问级别。因为我们一般都是在开发一个`app bundle`。
|
||||
|
||||
<a name="access_levels_for_single-target_apps"></a>
|
||||
### 单目标应用程序的访问级别
|
||||
@ -79,9 +82,14 @@ Swift 提供了三种不同的访问级别。这些访问级别相对于源文
|
||||
|
||||
<a name="access_levels_for_frameworks"></a>
|
||||
### Framework的访问级别
|
||||
当你开发`Framework`时,就需要把一些实体定义为`public`级别,以便其他人导入该`Framework`后可以正常使用其功能。这些被你定义为`public`的实体,就是这个`Framework`的API。
|
||||
当你开发`Framework`时,就需要把一些对外的接口定义为`public`级别,以便其他人导入该`Framework`后可以正常使用其功能。这些被你定义为`public`的接口,就是这个`Framework`的API。
|
||||
|
||||
> 注意:`Framework`的内部实现细节依然可以使用默认的`internal`级别,或者也可以定义为`private`级别。只有你想将它作为 API 的实体,才将其定义为`public`级别。
|
||||
> 注意:`Framework`的内部实现细节依然可以使用默认的`internal`级别,或者也可以定义为`private`级别。只有当你想把它作为 API 的一部分的时候,才将其定义为`public`级别。
|
||||
|
||||
<a name="access_levels_for_unit_test_targets"></a>
|
||||
### 单元测试目标的访问级别
|
||||
|
||||
当你的app有单元测试目标时,为了方便测试,测试模块需要能访问到你app中的代码。默认情况下只有`public`级别的实体才可以被其他模块访问。然而,如果在引入一个生产模块时使用`@testable`注解,然后用带测试的方式编译这个生产模块,单元测试目标就可以访问所有`internal`级别的实体。
|
||||
|
||||
<a name="access_control_syntax"></a>
|
||||
## 访问控制语法
|
||||
@ -97,7 +105,7 @@ internal let someInternalConstant = 0
|
||||
private func somePrivateFunction() {}
|
||||
```
|
||||
|
||||
除非有特殊的说明,否则实体都使用默认的访问级别`internal`,可以查阅**默认访问级别**这一节。这意味着`SomeInternalClass`和`someInternalConstant`不用明确的使用修饰符声明访问级别,但是他们任然拥有隐式的访问级别`internal`:
|
||||
除非有特殊的说明,否则实体都使用默认的访问级别`internal`,可以查阅**[默认访问级别](#default_access_levels)**这一节。这意味着在不使用修饰符声明显式访问级别的情况下,`SomeInternalClass`和`someInternalConstant`仍然拥有隐式的访问级别`internal`:
|
||||
|
||||
```swift
|
||||
class SomeInternalClass {} // 隐式访问级别 internal
|
||||
@ -105,40 +113,40 @@ var someInternalConstant = 0 // 隐式访问级别 internal
|
||||
```
|
||||
<a name="custom_types"></a>
|
||||
## 自定义类型
|
||||
如果你想为一个自定义类型指定一个明确的访问级别,那么你要明确一点。那就是你要确保新类型的访问级别和它实际的作用域相匹配。比如说,如果某个类里的属性、函数、返回值它们的作用域仅在当前的源文件中,那么你就可以将这个类申明为`private`类,而不需要申明为`public`或者`internal`类。
|
||||
如果想为一个自定义类型申明显式访问级别,那么要明确一点。那就是你要确保新类型的访问级别和它实际的作用域相匹配。比如说,如果你定义了一个`private`类,那这个类就只能在定义它的源文件中当作属性类型、函数参数或者返回类型使用。
|
||||
|
||||
类的访问级别也可以影响到类成员(属性、函数、初始化方法等)的默认访问级别。如果你将类申明为`private`类,那么该类的所有成员的默认访问级别也会成为`private`。如果你将类申明为`public`或者`internal`类(或者不明确的指定访问级别,而使用默认的`internal`访问级别),那么该类的所有成员的访问级别是`internal`。
|
||||
类的访问级别也可以影响到类成员(属性、函数、初始化方法等)的默认访问级别。如果你将类申明为`private`类,那么该类的所有成员的默认访问级别也会成为`private`。如果你将类申明为`public`或者`internal`类(或者不明确的申明访问级别,而使用默认的`internal`访问级别),那么该类的所有成员的访问级别是`internal`。
|
||||
|
||||
> 注意:上面提到,一个`public`类的所有成员的访问级别默认为`internal`级别,而不是`public`级别。如果你想将某个成员申明为`public`级别,那么你必须使用修饰符明确的申明该成员。这样做的好处是,在你定义公共接口API的时候,可以明确的选择哪些属性或方法是需要公开的,哪些是内部使用的,可以避免将内部使用的属性方法公开成公共API的错误。
|
||||
> 注意:上面提到,一个`public`类的所有成员的访问级别默认为`internal`级别,而不是`public`级别。如果你想将某个成员申明为`public`级别,那么你必须使用修饰符明确的声明该成员。这样做的好处是,在你定义公共接口API的时候,可以明确的选择哪些属性或方法是需要公开的,哪些是内部使用的,可以避免将内部使用的属性方法公开成公共API的错误。
|
||||
|
||||
```swift
|
||||
public class SomePublicClass { // 显示的 public 类
|
||||
public var somePublicProperty = 0 // 显示的 public 类成员
|
||||
public class SomePublicClass { // 显式的 public 类
|
||||
public var somePublicProperty = 0 // 显式的 public 类成员
|
||||
var someInternalProperty = 0 // 隐式的 internal 类成员
|
||||
private func somePrivateMethod() {} // 显示的 private 类成员
|
||||
private func somePrivateMethod() {} // 显式的 private 类成员
|
||||
}
|
||||
|
||||
class SomeInternalClass { // 隐式的 internal 类
|
||||
var someInternalProperty = 0 // 隐式的 internal 类成员
|
||||
private func somePrivateMethod() {} // 显示的 private 类成员
|
||||
private func somePrivateMethod() {} // 显式的 private 类成员
|
||||
}
|
||||
|
||||
private class SomePrivateClass { // 显示的 private 类
|
||||
private class SomePrivateClass { // 显式的 private 类
|
||||
var somePrivateProperty = 0 // 隐式的 private 类成员
|
||||
func somePrivateMethod() {} // 隐式的 private 类成员
|
||||
}
|
||||
```
|
||||
<a name="tuple_types"></a>
|
||||
### 元组类型
|
||||
元组的访问级别使用是所有类型的访问级别使用中最为严谨的。比如说,如果你构建一个包含两种不同类型元素的元组,其中一个元素类型的访问级别为`internal`,另一个为`private`级别,那么这个元组的访问级别为`private`。也就是说元组的访问级别遵循它里面元组中最低级的访问级别。
|
||||
元组的访问级别使用是所有类型的访问级别使用中最为严谨的。比如说,如果你构建一个包含两种不同类型元素的元组,其中一个元素类型的访问级别为`internal`,另一个为`private`级别,那么这个元组的访问级别为`private`。也就是说元组的访问级别与元组中访问级别最低的类型一致。
|
||||
|
||||
> 注意:元组不同于类、结构体、枚举、函数那样有单独的定义。元组的访问级别是在它被使用时自动推导出的,而不是明确的申明。
|
||||
|
||||
<a name="function_types"></a>
|
||||
### 函数类型
|
||||
函数的访问级别需要根据该函数的参数类型访问级别、返回类型访问级别得出。如果根据参数类型和返回类型得出的函数访问级别不符合上下文,那么就需要明确的申明该函数的访问级别。
|
||||
函数的访问级别需要根据该函数的参数类型和返回类型的访问级别得出。如果根据参数类型和返回类型得出的函数访问级别不符合默认上下文,那么就需要明确地申明该函数的访问级别。
|
||||
|
||||
下面的例子中定义了一个全局函数名为`someFunction`,并且没有明确的申明其访问级别。你也许会认为该函数应该拥有默认的访问级别`internal`,但事实并非如此。事实上,如果按下面这种写法,编译器是无法编译通过的:
|
||||
下面的例子定义了一个名为`someFunction`全局函数,并且没有明确地申明其访问级别。也许你会认为该函数应该拥有默认的访问级别`internal`,但事实并非如此。事实上,如果按下面这种写法,带埋是无法编译通过的:
|
||||
|
||||
```swift
|
||||
func someFunction() -> (SomeInternalClass, SomePrivateClass) {
|
||||
@ -146,9 +154,9 @@ func someFunction() -> (SomeInternalClass, SomePrivateClass) {
|
||||
}
|
||||
```
|
||||
|
||||
我们可以看到,这个函数的返回类型是一个元组,该元组中包含两个自定义的类(可查阅**自定义类型**)。其中一个类的访问级别是`internal`,另一个的访问级别是`private`,所以根据元组访问级别的原则,该元组的访问级别是`private`(元组的访问级别遵循它里面元组中最低级的访问级别)。
|
||||
我们可以看到,这个函数的返回类型是一个元组,该元组中包含两个自定义的类(可查阅**[自定义类型](#custom_types)**)。其中一个类的访问级别是`internal`,另一个的访问级别是`private`,所以根据元组访问级别的原则,该元组的访问级别是`private`(元组的访问级别与元组中访问级别最低的类型一致)。
|
||||
|
||||
因为该函数返回类型的访问级别是`private`,所以你必须使用`private`修饰符,明确的申请该函数:
|
||||
因为该函数返回类型的访问级别是`private`,所以你必须使用`private`修饰符,明确的声明该函数:
|
||||
|
||||
```swift
|
||||
private func someFunction() -> (SomeInternalClass, SomePrivateClass) {
|
||||
@ -160,7 +168,7 @@ private func someFunction() -> (SomeInternalClass, SomePrivateClass) {
|
||||
|
||||
<a name="enumeration_types"></a>
|
||||
### 枚举类型
|
||||
枚举中成员的访问级别继承自该枚举,你不能为枚举中的成员指定访问级别。
|
||||
枚举中成员的访问级别继承自该枚举,你不能为枚举中的成员单独申明不同的访问级别。
|
||||
|
||||
比如下面的例子,枚举`CompassPoint`被明确的申明为`public`级别,那么它的成员`North`,`South`,`East`,`West`的访问级别同样也是`public`:
|
||||
|
||||
@ -175,11 +183,11 @@ public enum CompassPoint {
|
||||
|
||||
<a name="raw_values_and_associated_values"></a>
|
||||
### 原始值和关联值
|
||||
用于枚举定义中的任何原始值,或关联的值类型必须有一个访问级别,至少要高于枚举的访问级别。比如说,你不能在一个`internal`访问级别的枚举中定义`private`级别的原始值类型。
|
||||
枚举定义中的任何原始值或关联值的类型都必须有一个访问级别,这个级别至少要不低于枚举的访问级别。比如说,你不能在一个`internal`访问级别的枚举中定义`private`级别的原始值类型。
|
||||
|
||||
<a name="nested_types"></a>
|
||||
### 嵌套类型
|
||||
如果在`private`级别的类型中定义嵌套类型,那么该嵌套类型就自动拥有`private`访问级别。如果在`public`或者`internal`级别的类型中定义嵌套类型,那么该嵌套类型自动拥有`internal`访问级别。如果想让嵌套类型拥有`public`访问级别,那么需要对该嵌套类型进行明确的访问级别申明。
|
||||
如果在`private`级别的类型中定义嵌套类型,那么该嵌套类型就自动拥有`private`访问级别。如果在`public`或者`internal`级别的类型中定义嵌套类型,那么该嵌套类型自动拥有`internal`访问级别。如果想让嵌套类型拥有`public`访问级别,那么需要明确地申明该嵌套类型的访问级别。
|
||||
|
||||
<a name="subclassing"></a>
|
||||
## 子类
|
||||
@ -217,7 +225,7 @@ internal class B: A {
|
||||
|
||||
<a name="constants_variables_properties_subscripts"></a>
|
||||
## 常量、变量、属性、下标
|
||||
常量、变量、属性不能拥有比它们的类型更高的访问级别。比如说,你定义一个`public`级别的属性,但是它的类型是`private`级别的,这是编译器不允许的。同样,下标也不能拥有比索引类型或返回类型更高的访问级别。
|
||||
常量、变量、属性不能拥有比它们的类型更高的访问级别。比如说,你定义一个`public`级别的属性,但是它的类型是`private`级别的,这是编译器所不允许的。同样,下标也不能拥有比索引类型或返回类型更高的访问级别。
|
||||
|
||||
如果常量、变量、属性、下标索引的定义类型是`private`级别的,那么它们必须要明确的申明访问级别为`private`:
|
||||
|
||||
@ -229,11 +237,11 @@ private var privateInstance = SomePrivateClass()
|
||||
### Getter和Setter
|
||||
常量、变量、属性、下标索引的`Getters`和`Setters`的访问级别继承自它们所属成员的访问级别。
|
||||
|
||||
`Setter`的访问级别可以低于对应的`Getter`的访问级别,这样就可以控制变量、属性或下标索引的读写权限。在`var`或`subscript`定义作用域之前,你可以通过`private(set)`或`internal(set)`先为它门的写权限申明一个较低的访问级别。
|
||||
`Setter`的访问级别可以低于对应的`Getter`的访问级别,这样就可以控制变量、属性或下标索引的读写权限。在`var`或`subscript`定义作用域之前,你可以通过`private(set)`或`internal(set)`先为它们的写权限申明一个较低的访问级别。
|
||||
|
||||
> 注意:这个规定适用于用作存储的属性或用作计算的属性。即使你不明确的申明存储属性的`Getter`、`Setter`,Swift也会隐式的为其创建`Getter`和`Setter`,用于对该属性进行读取操作。使用`private(set)`和`internal(set)`可以改变Swift隐式创建的`Setter`的访问级别。在计算属性中也是同样的。
|
||||
> 注意:这个规定适用于用作存储的属性或用作计算的属性。即使你不明确地申明存储属性的`Getter`、`Setter`,Swift也会隐式的为其创建`Getter`和`Setter`,用于对该属性进行读取操作。使用`private(set)`和`internal(set)`可以改变Swift隐式创建的`Setter`的访问级别。这对计算属性也同样适用。
|
||||
|
||||
下面的例子中定义了一个结构体名为`TrackedString`,它记录了`value`属性被修改的次数:
|
||||
下面的例子中定义了一个名为`TrackedString`的结构体,它记录了`value`属性被修改的次数:
|
||||
|
||||
```swift
|
||||
struct TrackedString {
|
||||
@ -247,11 +255,11 @@ struct TrackedString {
|
||||
```
|
||||
|
||||
|
||||
`TrackedString`结构体定义了一个用于存储的属性名为`value`,类型为`String`,并将初始化值设为`""`(即一个空字符串)。该结构体同时也定义了另一个用于存储的属性名为`numberOfEdits`,类型为`Int`,它用于记录属性`value`被修改的次数。这个功能的实现通过属性`value`的`didSet`方法实现,每当给`value`赋新值时就会调用`didSet`方法,给`numberOfEdits`加一。
|
||||
`TrackedString`结构体定义了一个用于存储`String`类型的属性`value`,并将初始化值设为`""`(即一个空字符串)。该结构体同时也定义了另一个用于存储`Int`类型的属性名`numberOfEdits`,它用于记录属性`value`被修改的次数。这个功能的实现通过属性`value`的`didSet`方法实现,每当给`value`赋新值时就会调用`didSet`方法,然后将`numberOfEdits`的值加一。
|
||||
|
||||
结构体`TrackedString`和它的属性`value`均没有明确的申明访问级别,所以它们都拥有默认的访问级别`internal`。但是该结构体的`numberOfEdits`属性使用`private(set)`修饰符进行申明,这意味着`numberOfEdits`属性只能在定义该结构体的源文件中赋值。`numberOfEdits`属性的`Getter`依然是默认的访问级别`internal`,但是`Setter`的访问级别是`private`,这表示该属性只有在当前的源文件中是可读可写的,在当前源文件所属的模块中它只是一个可读的属性。
|
||||
结构体`TrackedString`和它的属性`value`均没有申明显式访问级别,所以它们都拥有默认的访问级别`internal`。但是该结构体的`numberOfEdits`属性使用`private(set)`修饰符进行申明,这意味着`numberOfEdits`属性只能在定义该结构体的源文件中赋值。`numberOfEdits`属性的`Getter`依然是默认的访问级别`internal`,但是`Setter`的访问级别是`private`,这表示该属性只有在当前的源文件中是可读写的,而在当前源文件所属的模块中它只是一个可读的属性。
|
||||
|
||||
如果你实例化`TrackedString`结构体,并且多次对`value`属性的值进行修改,你就会看到`numberOfEdits`的值会随着修改次数更改:
|
||||
如果你实例化`TrackedString`结构体,并且多次对`value`属性的值进行修改,你就会看到`numberOfEdits`的值会随着修改次数进行变化:
|
||||
|
||||
```swift
|
||||
var stringToEdit = TrackedString()
|
||||
@ -264,9 +272,23 @@ println("The number of edits is \(stringToEdit.numberOfEdits)")
|
||||
|
||||
虽然你可以在其他的源文件中实例化该结构体并且获取到`numberOfEdits`属性的值,但是你不能对其进行赋值。这样就能很好的告诉使用者,你只管使用,而不需要知道其实现细节。
|
||||
|
||||
如果有必要你可以为`Getter`和`Setter`方法设定显式访问级别。下面的例子就是明确申明了`public`访问级别的`TrackedString`结构体。结构体的成员(包括`numberOfEdits`属性)拥有默认的访问级别`internal`。你可以结合`public`和`private(set)`修饰符把结构体中的`numberOfEdits`属性`Getter`方法的访问级别设置为`public`,而`Setter`方法的访问级别设置为`private`:
|
||||
|
||||
```swift
|
||||
public struct TrackedString {
|
||||
public private(set) var numberOfEdits = 0
|
||||
public var value: String = "" {
|
||||
didSet {
|
||||
numberOfEdits++
|
||||
}
|
||||
}
|
||||
public init() {}
|
||||
}
|
||||
```
|
||||
|
||||
<a name="initializers"></a>
|
||||
## 初始化
|
||||
我们可以给自定义的初始化方法指定访问级别,但是必须要低于或等于它所属类的访问级别。但如果该初始化方法是必须要使用的话,那它的访问级别就必须和所属类的访问级别相同。
|
||||
我们可以给自定义的初始化方法申明访问级别,但是要不高于它所属类的访问级别。但[必要构造器](TODO)例外,它的访问级别必须和所属类的访问级别相同。
|
||||
|
||||
如同函数或方法参数,初始化方法参数的访问级别也不能低于初始化方法的访问级别。
|
||||
|
||||
@ -284,7 +306,7 @@ Swift为结构体、类都提供了一个默认的无参初始化方法,用于
|
||||
|
||||
<a name="protocols"></a>
|
||||
## 协议
|
||||
如果你想为一个协议明确的申明访问级别,那么有一点需要注意,就是你要确保该协议只在你申明的访问级别作用域中使用。
|
||||
如果想为一个协议明确的申明访问级别,那么需要注意一点,就是你要确保该协议只在你申明的访问级别作用域中使用。
|
||||
|
||||
协议中的每一个必须要实现的函数都具有和该协议相同的访问级别。这样才能确保该协议的使用者可以实现它所提供的函数。
|
||||
|
||||
@ -298,17 +320,17 @@ Swift为结构体、类都提供了一个默认的无参初始化方法,用于
|
||||
### 协议一致性
|
||||
类可以采用比自身访问级别低的协议。比如说,你可以定义一个`public`级别的类,可以让它在其他模块中使用,同时它也可以采用一个`internal`级别的协议,并且只能在定义了该协议的模块中使用。
|
||||
|
||||
采用了协议的类的访问级别遵循它本身和采用协议中最低的访问级别。也就是说如果一个类是`public`级别,采用的协议是`internal`级别,那个采用了这个协议后,该类的访问级别也是`internal`。
|
||||
采用了协议的类的访问级别取它本身和所采用协议中最低的访问级别。也就是说如果一个类是`public`级别,采用的协议是`internal`级别,那么采用了这个协议后,该类的访问级别也是`internal`。
|
||||
|
||||
如果你采用了协议,那么实现了协议必须的方法后,该方法的访问级别遵循协议的访问级别。比如说,一个`public`级别的类,采用了`internal`级别的协议,那么该类实现协议的方法至少也得是`internal`。
|
||||
如果你采用了协议,那么实现了协议所必须的方法后,该方法的访问级别遵循协议的访问级别。比如说,一个`public`级别的类,采用了`internal`级别的协议,那么该类实现协议的方法至少也得是`internal`。
|
||||
|
||||
> 注意:在Swift中和Objective-C中一样,协议的一致性保证了一个类不可能在同一个程序中用不同的方法采用同一个协议。
|
||||
> 注意:Swift和Objective-C一样,协议的一致性保证了一个类不可能在同一个程序中用不同的方法采用同一个协议。
|
||||
|
||||
<a name="extensions"></a>
|
||||
## 扩展
|
||||
你可以在条件允许的情况下对类、结构体、枚举进行扩展。扩展成员应该具有和原始类成员一致的访问级别。比如你扩展了一个公共类型,那么你新加的成员应该具有和原始成员一样的默认的`internal`访问级别。
|
||||
|
||||
或者,你可以明确申明扩展的访问级别(比如使用`private extension`)给该扩展内所有成员指定一个新的默认访问级别。这个新的默认访问级别仍然可以被单独成员所指定的访问级别所覆盖。
|
||||
或者,你可以明确申明扩展的访问级别(比如使用`private extension`)给该扩展内所有成员申明一个新的默认访问级别。这个新的默认访问级别仍然可以被单独成员所申明的访问级别所覆盖。
|
||||
|
||||
<a name="adding_protocol_conformance_with_an_extension"></a>
|
||||
### 协议的扩展
|
||||
@ -316,12 +338,13 @@ Swift为结构体、类都提供了一个默认的无参初始化方法,用于
|
||||
|
||||
<a name="generics"></a>
|
||||
## 泛型
|
||||
泛型类型或泛型函数的访问级别遵循泛型类型、函数本身、泛型类型参数三者中访问级别最低的级别。
|
||||
泛型类型或泛型函数的访问级别取泛型类型、函数本身、泛型类型参数三者中的最低访问级别。
|
||||
|
||||
<a name="type_aliases"></a>
|
||||
## 类型别名
|
||||
任何被你定义的类型别名都会被视作为不同的类型,这些类型用于访问控制。一个类型别名的访问级别可以低于或等于这个类型的访问级别。比如说,一个`private`级别的类型别名可以设定给一个`public`、`internal`、`private`的类型,但是一个`public`级别的类型别名只能设定给一个`public`级别的类型,不能设定给`internal`或`private`的类类型。
|
||||
任何你定义的类型别名都会被当作不同的类型,以便于进行访问控制。一个类型别名的访问级别不可高于原类型的访问级别。比如说,一个`private`级别的类型别名可以设定给一个`public`、`internal`、`private`的类型,但是一个`public`级别的类型别名只能设定给一个`public`级别的类型,不能设定给`internal`或`private` 级别的类型。
|
||||
|
||||
> 注意:这条规则也适用于为满足协议一致性而给相关类型命名别名的情况。
|
||||
|
||||
> 注意:这条规则也适用于为满足协议一致性而给相关类型命名别名。
|
||||
|
||||
|
||||
|
||||
@ -12,75 +12,75 @@
|
||||
- [运算符函数(Operator Functions)](#operator_functions)
|
||||
- [自定义运算符](#custom_operators)
|
||||
|
||||
除了[基本操作符](02_Basic_Operators.html)中所讲的运算符,Swift还有许多复杂的高级运算符,包括了C语言和Objective-C中的位运算符和移位运算。
|
||||
除了在之前介绍过的[基本运算符](02_Basic_Operators.html),Swift 中还有许多可以对数值进行复杂操作的高级运算符。这些高级运算符包含了在 C 和 Objective-C 中已经被大家所熟知的位运算符和移位运算符。
|
||||
|
||||
不同于C语言中的数值计算,Swift的数值计算默认是不可溢出的。溢出行为会被捕获并报告为错误。你是故意的?好吧,你可以使用Swift为你准备的另一套默认允许溢出的数值运算符,如可溢出的加号为`&+`。所有允许溢出的运算符都是以`&`开始的。
|
||||
与C语言中的算术运算符不同,Swift 中的算术运算符默认是不会溢出的。所有溢出行为都会被捕获并报告为错误。如果想让系统允许溢出行为,可以选择使用 Swift 中另一套默认支持溢出的运算符,比如溢出加法运算符(`&+`)。所有的这些溢出运算符都是以 `&` 开头的。
|
||||
|
||||
自定义的结构,类和枚举,是否可以使用标准的运算符来定义操作?当然可以!在Swift中,你可以为你创建的所有类型定制运算符的操作。
|
||||
在定义自有的结构体、类和枚举时,最好也同时为它们提供标准swift运算符的实现。Swift简化了运算符的自定义实现,也使判断不同类型所对应的行为更为简单。
|
||||
|
||||
可定制的运算符并不限于那些预设的运算符,你可以自定义中置,前置,后置及赋值运算符,当然还有优先级和结合性。这些运算符在代码中可以像预设的运算符一样使用,你也可以扩展已有的类型以支持你自定义的运算符。
|
||||
我们不用被预定义的运算符所限制。在 Swift 当中可以自由地定义中缀、前缀、后缀和赋值运算符,以及相应的优先级与结合性。这些运算符在代码中可以像预设的运算符一样使用,我们甚至可以扩展已有的类型以支持自定义的运算符。
|
||||
|
||||
<a name="bitwise_operators"></a>
|
||||
## 位运算符
|
||||
|
||||
位操作符可以操作数据结构中原始数据的每个比特位。位操作符通常在诸如图像处理和创建设备驱动等底层开发中使用,位操作符在同外部资源的数据进行交互的时候也很有用,比如在使用用户协议进行通信的时候,运用位运算符来对原始数据进行编码和解码。
|
||||
位运算符(`Bitwise operators`)可以操作一个数据结构中每个独立的位。它们通常被用在底层开发中,比如图形编程和创建设备驱动。位运算符在处理外部资源的原始数据时也十分有用,比如对自定义通信协议传输的数据进行编码和解码。
|
||||
|
||||
Swift支持如下所有C语言的位运算符:
|
||||
Swift 支持C语言中的全部位运算符,具体如下:
|
||||
|
||||
### 按位取反运算符
|
||||
### 按位取反运算符(`bitwise NOT operator`)
|
||||
|
||||
按位取反运算符`~`对一个操作数的每一位都取反。
|
||||
按位取反运算符(`~`) 可以对一个数值的全部位进行取反:
|
||||
|
||||

|
||||

|
||||
|
||||
这个运算符是前置的,所以请不加任何空格地写在操作数之前。
|
||||
按位取反操作符是一个前置运算符,需要直接放在操作数的之前,并且它们之间不能添加任何空格。
|
||||
|
||||
```swift
|
||||
```
|
||||
let initialBits: UInt8 = 0b00001111
|
||||
let invertedBits = ~initialBits // 等于 0b11110000
|
||||
```
|
||||
|
||||
`UInt8`是8位无符整型,可以存储0~255之间的任意数。这个例子初始化一个整型为二进制值`00001111`(前4位为`0`,后4位为`1`),它的十进制值为`15`。
|
||||
`UInt8` 类型的整数有 8 个比特位,可以存储 0 ~ 255之间的任意整数。这个例子初始化了一个 `UInt8` 类型的整数,并赋值为二进制的 `00001111`,它的前 4 位都为`0`,后 4 位都为`1`。这个值等价于十进制的 `15` 。
|
||||
|
||||
使用按位取反运算`~`对`initialBits`操作,然后赋值给`invertedBits`这个新常量。这个新常量的值等于所有位都取反的`initialBits`,即`1`变成`0`,`0`变成`1`,变成了`11110000`,十进制值为`240`。
|
||||
接着使用按位取反运算符创建了一个名为 `invertedBits` 的常量,这个常量的值与全部位取反后的 `initialBits` 相等。即所有的 `0` 都变成了 `1`,同时所有的 `1` 都变成 `0`。`invertedBits` 的二进制值为 `11110000`,等价于无符号十进制数的 `240`。
|
||||
|
||||
### 按位与运算符
|
||||
### 按位与运算符(Bitwise AND Operator)
|
||||
|
||||
按位与运算符对两个数进行操作,然后返回一个新的数,这个数的每个位都需要两个输入数的同一位都为1时才为1。
|
||||
按位与运算符(`&`)可以对两个数的比特位进行合并。它返回一个新的数,只有当两个操作数的对应位*都*为 `1` 的时候,该数的对应位才为 `1`。
|
||||
|
||||

|
||||
|
||||
以下代码,`firstSixBits`和`lastSixBits`中间4个位都为1。对它俩进行按位与运算后,就得到了`00111100`,即十进制的`60`。
|
||||
在下面的示例当中,`firstSixBits` 和 `lastSixBits` 中间 4 个位的值都为 1 。按位与运算符对它们进行了运算,得到二进制数值 `00111100`,等价于无符号十进制数的 `60`:
|
||||
|
||||
```swift
|
||||
```
|
||||
let firstSixBits: UInt8 = 0b11111100
|
||||
let lastSixBits: UInt8 = 0b00111111
|
||||
let middleFourBits = firstSixBits & lastSixBits // 等于 00111100
|
||||
```
|
||||
|
||||
### 按位或运算
|
||||
### 按位或运算符(Bitwise OR Operator)
|
||||
|
||||
按位或运算符`|`比较两个数,然后返回一个新的数,这个数的每一位设置1的条件是两个输入数的同一位都不为0(即任意一个为1,或都为1)。
|
||||
按位或运算符(`|`)可以对两个数的比特位进行比较。它返回一个新的数,只要两个操作数的对应位中有*任意*一个为 `1` 时,该数的对应位就为 `1`。
|
||||
|
||||

|
||||
|
||||
如下代码,`someBits`和`moreBits`在不同位上有`1`。按位或运行的结果是`11111110`,即十进制的`254`。
|
||||
在下面的示例当中,`someBits` 和 `moreBits` 将不同的位设置为 `1`。接位或运算符对它们进行了运算,得到二进制数值 `11111110`,等价于无符号十进制数的 `254`:
|
||||
|
||||
```swift
|
||||
```
|
||||
let someBits: UInt8 = 0b10110010
|
||||
let moreBits: UInt8 = 0b01011110
|
||||
let combinedbits = someBits | moreBits // 等于 11111110
|
||||
```
|
||||
|
||||
### 按位异或运算符
|
||||
### 按位异或运算符(Bitwise XOR Opoerator)
|
||||
|
||||
按位异或运算符`^`比较两个数,然后返回一个数,这个数的每个位设为`1`的条件是两个输入数的同一位不同,如果相同就设为`0`。
|
||||
按位异或运算符(`^`)可以对两个数的比特位进行比较。它返回一个新的数,当两个操作数的对应位不相同时,该数的对应位就为 `1`:
|
||||
|
||||

|
||||
|
||||
以下代码,`firstBits`和`otherBits`都有一个`1`跟另一个数不同的。所以按位异或的结果是把它这些位置为`1`,其他都置为`0`。
|
||||
在下面的示例当中,`firstBits` 和 `otherBits` 都有一个自己设置为 `1` 而对方设置为 `0` 的位。 按位异或运算符将这两个位都设置为 `1`,同时将其它位都设置为 `0`:
|
||||
|
||||
```swift
|
||||
```
|
||||
let firstBits: UInt8 = 0b00010100
|
||||
let otherBits: UInt8 = 0b00000101
|
||||
let outputBits = firstBits ^ otherBits // 等于 00010001
|
||||
@ -88,21 +88,27 @@ let outputBits = firstBits ^ otherBits // 等于 00010001
|
||||
|
||||
### 按位左移/右移运算符
|
||||
|
||||
左移运算符`<<`和右移运算符`>>`会把一个数的所有比特位按以下定义的规则向左或向右移动指定位数。
|
||||
按位左移运算符(`<<`)和按位右移运算符(`>>`)可以对一个数进行指定位数的左移和右移,但是需要遵守下面定义的规则。
|
||||
|
||||
按位左移和按位右移的效果相当把一个整数乘于或除于一个因子为`2`的整数。向左移动一个整型的比特位相当于把这个数乘于`2`,向右移一位就是除于`2`。
|
||||
对一个数进行按位左移或按位右移,相当于对这个数进行乘以 2 或除以 2 的运算。将一个整数左移一位,等价于将这个数乘以 2,同样地,将一个整数右移一位,等价于将这个数除以 2。
|
||||
|
||||
#### 无符整型的移位操作
|
||||
#### 无符号整型的移位操作
|
||||
|
||||
对无符整型的移位的效果如下:
|
||||
对无符号整型进行移位的规则如下:
|
||||
|
||||
已经存在的比特位向左或向右移动指定的位数。被移出整型存储边界的的位数直接抛弃,移动留下的空白位用零`0`来填充。这种方法称为逻辑移位。
|
||||
1. 已经存在的比特位按指定的位数进行左移和右移。
|
||||
2. 任何移动超出整型存储边界的位都会被丢弃。
|
||||
3. 用 0 来填充移动后产生的空白位。
|
||||
|
||||
以下这张把展示了 `11111111 << 1`(`11111111`向左移1位),和 `11111111 >> 1`(`11111111`向右移1位)。蓝色的是被移位的,灰色是被抛弃的,橙色的`0`是被填充进来的。
|
||||
这种方法称为逻辑移位(`logical shift`)。
|
||||
|
||||
以下这张图展示了 `11111111 << 1`(即把 `11111111` 向左移动 1 位),和 `11111111 >> 1`(即把 `11111111` 向右移动 1 位) 的结果。蓝色的部分是被移位的,灰色的部分是被抛弃的,橙色的部分则是被填充进来的。
|
||||
|
||||

|
||||
|
||||
```swift
|
||||
下面的代码演示了 Swift 中的移位操作:
|
||||
|
||||
```
|
||||
let shiftBits: UInt8 = 4 // 即二进制的00000100
|
||||
shiftBits << 1 // 00001000
|
||||
shiftBits << 2 // 00010000
|
||||
@ -111,221 +117,205 @@ shiftBits << 6 // 00000000
|
||||
shiftBits >> 2 // 00000001
|
||||
```
|
||||
|
||||
你可以使用移位操作进行其他数据类型的编码和解码。
|
||||
可以使用移位操作对其他的数据类型进行编码和解码:
|
||||
|
||||
```swift
|
||||
```
|
||||
let pink: UInt32 = 0xCC6699
|
||||
let redComponent = (pink & 0xFF0000) >> 16 // redComponent 是 0xCC, 即 204
|
||||
let greenComponent = (pink & 0x00FF00) >> 8 // greenComponent 是 0x66, 即 102
|
||||
let blueComponent = pink & 0x0000FF // blueComponent 是 0x99, 即 153
|
||||
```
|
||||
|
||||
这个例子使用了一个`UInt32`的命名为`pink`的常量来存储层叠样式表`CSS`中粉色的颜色值,`CSS`颜色`#CC6699`在Swift用十六进制`0xCC6699`来表示。然后使用按位与(&)和按位右移就可以从这个颜色值中解析出红(CC),绿(66),蓝(99)三个部分。
|
||||
这个示例使用了一个命名为 `pink` 的 `UInt32` 型常量来存储层叠样式表(`CSS`)中粉色的颜色值。该 `CSS` 的十六进制颜色值 `#CC6699`, 在 Swift 中表示为 `0xCC6699`。然后利用按位与运算符(`&`)和按位右移运算符(`>>`)从这个颜色值中分解出红(`CC`)、绿(`66`)以及蓝(`99`)三个部分。
|
||||
|
||||
对`0xCC6699`和`0xFF0000`进行按位与`&`操作就可以得到红色部分。`0xFF0000`中的`0`了遮盖了`OxCC6699`的第二和第三个字节,这样`6699`被忽略了,只留下`0xCC0000`。
|
||||
红色部分是通过对 `0xCC6699` 和 `0xFF0000` 进行按位与运算后得到的。`0xFF0000` 中的 `0` 部分作为*掩码*,掩盖了 `OxCC6699` 中的第二和第三个字节,使得数值中的 `6699` 被忽略,只留下 `0xCC0000`。
|
||||
|
||||
然后,按向右移动16位,即 `>> 16`。十六进制中每两个字符是8比特位,所以移动16位的结果是把`0xCC0000`变成`0x0000CC`。这和`0xCC`是相等的,就是十进制的`204`。
|
||||
然后,再将这个数按向右移动 16 位(`>> 16`)。十六进制中每两个字符表示 8 个比特位,所以移动 16 位后 `0xCC0000` 就变为 `0x0000CC`。这个数和`0xCC`是等同的,也就是十进制数值的 `204`。
|
||||
|
||||
同样的,绿色部分来自于`0xCC6699`和`0x00FF00`的按位操作得到`0x006600`。然后向右移动8位,得到`0x66`,即十进制的`102`。
|
||||
同样的,绿色部分通过对 `0xCC6699` 和 `0x00FF00` 进行按位与运算得到 `0x006600`。然后将这个数向右移动 8 位,得到 `0x66`,也就是十进制数值的 `102`。
|
||||
|
||||
最后,蓝色部分对`0xCC6699`和`0x0000FF`进行按位与运算,得到`0x000099`,无需向右移位了,所以结果就是`0x99`,即十进制的`153`。
|
||||
最后,蓝色部分通过对 `0xCC6699` 和 `0x0000FF` 进行按位与运算得到 `0x000099`。并且不需要进行向右移位,所以结果为 `0x99` ,也就是十进制数值的 `153`。
|
||||
|
||||
#### 有符整型的移位操作
|
||||
#### 有符号整型的移位操作
|
||||
|
||||
有符整型的移位操作相对复杂得多,因为正负号也是用二进制位表示的。(这里举的例子虽然都是8位的,但它的原理是通用的。)
|
||||
对比无符号整型来说,有符整型的移位操作相对复杂得多,这种复杂性源于有符号整数的二进制表现形式。(为了简单起见,以下的示例都是基于 8 位有符号整数的,但是其中的原理对任何位数的有符号整数都是通用的。)
|
||||
|
||||
有符整型通过第1个比特位(称为符号位)来表达这个整数是正数还是负数。`0`代表正数,`1`代表负数。
|
||||
有符号整数使用第 1 个比特位(通常被称为符号位)来表示这个数的正负。符号位为 `0` 代表正数,为 `1` 代表负数。
|
||||
|
||||
其余的比特位(称为数值位)存储其实值。有符正整数和无符正整数在计算机里的存储结果是一样的,下来我们来看`+4`内部的二进制结构。
|
||||
其余的比特位(通常被称为数值位)存储了这个数的真实值。有符号正整数和无符号数的存储方式是一样的,都是从 `0` 开始算起。这是值为 `4` 的 `Int8` 型整数的二进制位表现形式:
|
||||
|
||||

|
||||
|
||||
符号位为`0`,代表正数,另外7比特位二进制表示的实际值就刚好是`4`。
|
||||
符号位为 `0`,说明这是一个正数,另外 7 位则代表了十进制数值 `4` 的二进制表示。
|
||||
|
||||
负数呢,跟正数不同。负数存储的是2的n次方减去它的绝对值,n为数值位的位数。一个8比特的数有7个数值位,所以是2的7次方,即128。
|
||||
负数的存储方式略有不同。它存储的是 `2` 的 n 次方减去它的真实值绝对值,这里的 n 为数值位的位数。一个 8 位的数有 7 个数值位,所以是 2 的 7 次方,即 128。
|
||||
|
||||
我们来看`-4`存储的二进制结构。
|
||||
这是值为 `-4` 的 `Int8` 型整数的二进制位表现形式:
|
||||
|
||||

|
||||
|
||||
现在符号位为`1`,代表负数,7个数值位要表达的二进制值是124,即128 - 4。
|
||||
这次的符号位为 `1`,说明这是一个负数,另外 7 个位则代表了数值 `124`(即 `128 - 4`) 的二进制表示。
|
||||
|
||||

|
||||
|
||||
负数的编码方式称为二进制补码表示。这种表示方式看起来很奇怪,但它有几个优点。
|
||||
负数的表示通常被称为二进制补码(`two's complement`)表示法。用这种方法来表示负数乍看起来有点奇怪,但它有几个优点。
|
||||
|
||||
首先,只需要对全部8个比特位(包括符号)做标准的二进制加法就可以完成 `-1 + -4` 的操作,忽略加法过程产生的超过8个比特位表达的任何信息。
|
||||
首先,如果想对 `-1` 和 `-4` 进行加法操作,我们只需要将这两个数的全部 8 个比特位进行相加,并且将计算结果中超出 8 位的数值丢弃:
|
||||
|
||||

|
||||
|
||||
第二,由于使用二进制补码表示,我们可以和正数一样对负数进行按位左移右移的,同样也是左移1位时乘于`2`,右移1位时除于`2`。要达到此目的,对有符整型的右移有一个特别的要求:
|
||||
其次,使用二进制补码可以使负数的按位左移和右移操作得到跟正数同样的效果,即每向左移一位就将自身的数值乘以 2,每向右一位就将自身的数值除以 2。要达到此目的,对有符号整数的右移有一个额外的规则:
|
||||
|
||||
对有符整型按位右移时,不使用0填充空白位,而是根据符号位(正数为`0`,负数为`1`)填充空白位。
|
||||
* 当对正整数进行按位右移操作时,遵循与无符号整数相同的规则,但是对于移位产生的空白位使用*符号位*进行填充,而不是用 0。
|
||||
|
||||

|
||||
|
||||
这就确保了在右移的过程中,有符整型的符号不会发生变化。这称为算术移位。
|
||||
这个行为可以确保有符号整数的符号位不会因为右移操作而改变,这通常被称为算术移位(`arithmetic shift`)。
|
||||
|
||||
正因为正数和负数特殊的存储方式,向右移位使它接近于`0`。移位过程中保持符号会不变,负数在接近`0`的过程中一直是负数。
|
||||
由于正数和负数的特殊存储方式,在对它们进行右移的时候,会使它们越来越接近 0。在移位的过程中保持符号位不变,意味着负整数在接近 `0` 的过程中会一直保持为负。
|
||||
|
||||
<a name="overflow_operators"></a>
|
||||
## 溢出运算符
|
||||
|
||||
默认情况下,当你往一个整型常量或变量赋于一个它不能承载的大数时,Swift不会让你这么干的,它会报错。这样,在操作过大或过小的数的时候就很安全了。
|
||||
在默认情况下,当向一个整数赋超过它容量的值时,Swift 默认会报错,而不是生成一个无效的数。这个行为给我们操作过大或着过小的数的时候提供了额外的安全性。
|
||||
|
||||
例如,`Int16`整型能承载的整数范围是`-32768`到`32767`,如果给它赋上超过这个范围的数,就会报错:
|
||||
例如,`Int16` 型整数能容纳的有符号整数范围是 `-32768` 到 `32767`,当为一个 `Int16` 型变量赋的值超过这个范围时,系统就会报错:
|
||||
|
||||
```swift
|
||||
```
|
||||
var potentialOverflow = Int16.max
|
||||
// potentialOverflow 等于 32767, 这是 Int16 能承载的最大整数
|
||||
// potentialOverflow 的值是 32767, 这是 Int16 能容纳的最大整数
|
||||
|
||||
potentialOverflow += 1
|
||||
// 噢, 出错了
|
||||
// 这里会报错
|
||||
```
|
||||
|
||||
对过大或过小的数值进行错误处理让你的数值边界条件更灵活。
|
||||
为过大或者过小的数值提供错误处理,能让我们在处理边界值时更加灵活。
|
||||
|
||||
当然,你有意在溢出时对有效位进行截断,你可采用溢出运算,而非错误处理。Swfit为整型计算提供了5个`&`符号开头的溢出运算符。
|
||||
然而,也可以选择让系统在数值溢出的时候采取截断操作,而非报错。可以使用 Swift 提供的三个溢出操作符(`overflow operators`)来让系统支持整数溢出运算。这些操作符都是以 `&` 开头的:
|
||||
|
||||
- 溢出加法 `&+`
|
||||
- 溢出减法 `&-`
|
||||
- 溢出乘法 `&*`
|
||||
- 溢出除法 `&/`
|
||||
- 溢出求余 `&%`
|
||||
* 溢出加法 `&+`
|
||||
* 溢出减法 `&-`
|
||||
* 溢出乘法 `&*`
|
||||
|
||||
### 值的上溢出
|
||||
### 数值溢出
|
||||
|
||||
下面例子使用了溢出加法`&+`来解剖的无符整数的上溢出
|
||||
数值有可能出现上溢或者下溢。
|
||||
|
||||
```swift
|
||||
var willOverflow = UInt8.max
|
||||
// willOverflow 等于UInt8的最大整数 255
|
||||
willOverflow = willOverflow &+ 1
|
||||
// 此时 willOverflow 等于 0
|
||||
这个示例演示了当我们对一个无符号整数使用溢出加法(`&+`)进行上溢运算时会发生什么:
|
||||
```
|
||||
var unsignedOverflow = UInt8.max
|
||||
// unsignedOverflow 等于 UInt8 所能容纳的最大整数 255
|
||||
|
||||
unsignedOverflow = unsignedOverflow &+ 1
|
||||
// 此时 unsignedOverflow 等于 0
|
||||
```
|
||||
|
||||
`willOverflow`用`Int8`所能承载的最大值`255`(二进制`11111111`),然后用`&+`加1。然后`UInt8`就无法表达这个新值的二进制了,也就导致了这个新值上溢出了,大家可以看下图。溢出后,新值在`UInt8`的承载范围内的那部分是`00000000`,也就是`0`。
|
||||
`unsignedOverflow` 被初始化为 `UInt8` 所能容纳的最大整数(`255`,以二进制表示即 `11111111`)。然后使用了溢出加法运算符(`&+`)对其进行加 1 操作。这使得它的二进制表示正好超出 `UInt8` 所能容纳的位数,也就导致了数值的溢出,如下图所示。数值溢出后,留在 `UInt8` 边界内的值是 `00000000`,也就是十进制数值的 0。
|
||||
|
||||

|
||||
|
||||
### 值的下溢出
|
||||
同样地,当我们对一个无符号整数使用溢出减法(`&-`)进行下溢运算时也会产生类似的现象:
|
||||
|
||||
数值也有可能因为太小而越界。举个例子:
|
||||
```
|
||||
var unsignedOverflow = UInt8.min
|
||||
// unsignedOverflow 等于 UInt8 所能容纳的最小整数 0
|
||||
|
||||
`UInt8`的最小值是`0`(二进制为`00000000`)。使用`&-`进行溢出减1,就会得到二进制的`11111111`即十进制的`255`。
|
||||
|
||||

|
||||
|
||||
Swift代码是这样的:
|
||||
|
||||
```swift
|
||||
var willUnderflow = UInt8.min
|
||||
// willUnderflow 等于UInt8的最小值0
|
||||
willUnderflow = willUnderflow &- 1
|
||||
// 此时 willUnderflow 等于 255
|
||||
unsignedOverflow = unsignedOverflow &- 1
|
||||
// 此时 unsignedOverflow 等于 255
|
||||
```
|
||||
|
||||
有符整型也有类似的下溢出,有符整型所有的减法也都是对包括在符号位在内的二进制数进行二进制减法的,这在 "按位左移/右移运算符" 一节提到过。最小的有符整数是`-128`,即二进制的`10000000`。用溢出减法减去去1后,变成了`01111111`,即UInt8所能承载的最大整数`127`。
|
||||
`UInt8` 型整数能容纳的最小值是 0,以二进制表示即 `00000000`。当使用溢出减法运算符对其进行减 1 操作时,数值会产生下溢并被截断为 `11111111`, 也就是十进制数值的 255。
|
||||
|
||||

|
||||
|
||||
溢出也会发生在有符号整型数值上。在对有符号整型数值进行溢出加法或溢出减法运算时,符号位也需要参与计算,正如[按位左移/右移运算符](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/AdvancedOperators.html#//apple_ref/doc/uid/TP40014097-CH27-ID34)所描述的。
|
||||
|
||||
```
|
||||
var signedOverflow = Int8.min
|
||||
// signedOverflow 等于 Int8 所能容纳的最小整数 -128
|
||||
|
||||
signedOverflow = signedOverflow &- 1
|
||||
// 此时 signedOverflow 等于 127
|
||||
```
|
||||
|
||||
`Int8` 型整数能容纳的最小值是 -128,以二进制表示即 `10000000`。当使用溢出减法操作符对其进行减 1 操作时,符号位被翻转,得到二进制数值 `01111111`,也就是十进制数值的 `127`,这个值也是 `Int8` 型整数所能容纳的最大值。
|
||||
|
||||

|
||||
|
||||
来看看Swift代码:
|
||||
|
||||
```swift
|
||||
var signedUnderflow = Int8.min
|
||||
// signedUnderflow 等于最小的有符整数 -128
|
||||
signedUnderflow = signedUnderflow &- 1
|
||||
// 此时 signedUnderflow 等于 127
|
||||
```
|
||||
|
||||
### 除零溢出
|
||||
|
||||
一个数除以0 `i / 0`,或者对0求余数 `i % 0`,就会产生一个错误。
|
||||
|
||||
```swift
|
||||
let x = 1
|
||||
let y = x / 0
|
||||
```
|
||||
|
||||
使用它们对应的可溢出的版本的运算符`&/`和`&%`进行除0操作时就会得到`0`值。
|
||||
|
||||
```swift
|
||||
let x = 1
|
||||
let y = x &/ 0
|
||||
// y 等于 0
|
||||
```
|
||||
对于无符号与有符号整型数值来说,当出现上溢时,它们会从数值所能容纳的最大数变成最小的数。同样地,当发生下溢时,它们会从所能容纳的最小数变成最大的数。
|
||||
|
||||
<a name="precedence_and_associativity"></a>
|
||||
## 优先级和结合性
|
||||
|
||||
运算符的优先级使得一些运算符优先于其他运算符,高优先级的运算符会先被计算。
|
||||
运算符的优先级(`precedence`)使得一些运算符优先于其他运算符,高优先级的运算符会先被计算。
|
||||
|
||||
结合性定义相同优先级的运算符在一起时是怎么组合或关联的,是和左边的一组呢,还是和右边的一组。意思就是,到底是和左边的表达式结合呢,还是和右边的表达式结合?
|
||||
结合性(`associativity`)定义了相同优先级的运算符是如何结合(或关联)的 —— 是与左边结合为一组,还是与右边结合为一组。可以将这意思理解为“它们是与左边的表达式结合的”或者“它们是与右边的表达式结合的”。
|
||||
|
||||
在混合表达式中,运算符的优先级和结合性是非常重要的。举个例子,为什么下列表达式的结果为`4`?
|
||||
在复合表达式的运算顺序中,运算符的优先级和结合性是非常重要的。举例来说,为什么下面这个表达式的运算结果是 `4`?
|
||||
|
||||
```swift
|
||||
2 + 3 * 4 % 5
|
||||
// 结果是 4
|
||||
```
|
||||
|
||||
如果严格地从左计算到右,计算过程会是这样:
|
||||
|
||||
如果严格地从左到右进行运算,则运算的过程是这样的:
|
||||
|
||||
- 2 + 3 = 5
|
||||
- 5 * 4 = 20
|
||||
- 20 / 5 = 4 余 0
|
||||
- 20 % 5 = 0
|
||||
|
||||
但是正确答案是`4`而不是`0`。优先级高的运算符要先计算,在Swift和C语言中,都是先乘除后加减的。所以,执行完乘法和求余运算才能执行加减运算。
|
||||
但是正确答案是 `4` 而不是 `0`。优先级高的运算符要先于优先级低的运算符进行计算。与C语言类似,在 Swift 当中,乘法运算符(`*`)与取余运算符(`%`)的优先级高于加法运算符(`+`)。因此,它们的计算顺序要先于加法运算。
|
||||
|
||||
乘法和求余拥有相同的优先级,在运算过程中,我们还需要结合性,乘法和求余运算都是左结合的。这相当于在表达式中有隐藏的括号让运算从左开始。
|
||||
而乘法与取余的优先级相同。这时为了得到正确的运算顺序,还需要考虑结合性。乘法与取余运算都是左结合的。可以将这考虑成为这两部分表达式都隐式地加上了括号:
|
||||
|
||||
```swift
|
||||
2 + ((3 * 4) % 5)
|
||||
```
|
||||
|
||||
3 * 4 = 12,所以这相当于:
|
||||
`(3 * 4) = 12`,所以表达式相当于:
|
||||
|
||||
|
||||
```swift
|
||||
2 + (12 % 5)
|
||||
```
|
||||
|
||||
12 % 5 = 2,所这又相当于
|
||||
`12 % 5 = 2`,所以表达式相当于:
|
||||
|
||||
```swift
|
||||
2 + 2
|
||||
```
|
||||
|
||||
计算结果为 4。
|
||||
此时可以容易地看出计算的结果为 `4`。
|
||||
|
||||
查阅Swift运算符的优先级和结合性的完整列表,请看[表达式](../chapter3/04_Expressions.html)。
|
||||
如果想查看完整的 Swift 运算符优先级和结合性规则,请参考[表达式](../chapter3/04_Expressions.html)。
|
||||
|
||||
> 注意:
|
||||
Swift的运算符较C语言和Objective-C来得更简单和保守,这意味着跟基于C的语言可能不一样。所以,在移植已有代码到Swift时,注意去确保代码按你想的那样去执行。
|
||||
> 对于C语言和 Objective-C 来说,Swift 的运算符优先级和结合性规则是更加简洁和可预测的。但是,这也意味着它们于那些基于C的语言不是完全一致的。在对现有的代码进行移植的时候,要注意确保运算符的行为仍然是按照你所想的那样去执行。
|
||||
|
||||
<a name="operator_functions"></a>
|
||||
## 运算符函数
|
||||
|
||||
让已有的运算符也可以对自定义的类和结构进行运算,这称为运算符重载。
|
||||
类和结构可以为现有的操作符提供自定义的实现,这通常被称为运算符重载(`overloading`)。
|
||||
|
||||
这个例子展示了如何用`+`让一个自定义的结构做加法。算术运算符`+`是一个两目运算符,因为它有两个操作数,而且它必须出现在两个操作数之间。
|
||||
下面的例子展示了如何为自定义的结构实现加法操作符(`+`)。算术加法运算符是一个两目运算符(`binary operator`),因为它可以对两个目标进行操作,同时它还是中缀(`infix`)运算符,因为它出现在两个目标中间。
|
||||
|
||||
例子中定义了一个名为`Vector2D`的二维坐标向量 `(x,y)` 的结构,然后定义了让两个`Vector2D`的对象相加的运算符函数。
|
||||
例子中定义了一个名为 `Vector2D` 的结构体用来表示二维坐标向量`(x, y)`,紧接着定义了一个可以对两个 `Vector2D` 结构体进行相加的运算符函数(`operator function`):
|
||||
|
||||
```swift
|
||||
struct Vector2D {
|
||||
var x = 0.0, y = 0.0
|
||||
}
|
||||
@infix func + (left: Vector2D, right: Vector2D) -> Vector2D {
|
||||
|
||||
func + (left: Vector2D, right: Vector2D) -> Vector2D {
|
||||
return Vector2D(x: left.x + right.x, y: left.y + right.y)
|
||||
}
|
||||
```
|
||||
|
||||
该运算符函数定义了一个全局的`+`函数,这个函数需要两个`Vector2D`类型的参数,返回值也是`Vector2D`类型。需要定义和实现一个中置运算的时候,在关键字`func`之前写上属性 `@infix` 就可以了。
|
||||
该运算符函数被定义为一个全局函数,并且函数的名字与它要进行重载的 `+` 名字一致。因为算术加法运算符是双目运算符,所以这个运算符函数接收两个类型为 `Vector2D` 的输入参数,同时有一个 `Vector2D` 类型的返回值。
|
||||
|
||||
在这个代码实现中,参数被命名为了`left`和`right`,代表`+`左边和右边的两个`Vector2D`对象。函数返回了一个新的`Vector2D`的对象,这个对象的`x`和`y`分别等于两个参数对象的`x`和`y`的和。
|
||||
在这个实现中,输入参数分别被命名为 `left` 和 `right`,代表在 `+` 运算符左边和右边的两个 `Vector2D` 对象。函数返回了一个新的 `Vector2D` 的对象,这个对象的 `x` 和 `y` 分别等于两个参数对象的 `x` 和 `y` 的值之和。
|
||||
|
||||
这个函数是全局的,而不是`Vector2D`结构的成员方法,所以任意两个`Vector2D`对象都可以使用这个中置运算符。
|
||||
这个函数被定义成全局的,而不是 `Vector2D` 结构的成员方法,所以任意两个 `Vector2D` 对象都可以使用这个中缀运算符:
|
||||
|
||||
```swift
|
||||
let vector = Vector2D(x: 3.0, y: 1.0)
|
||||
@ -334,91 +324,91 @@ let combinedVector = vector + anotherVector
|
||||
// combinedVector 是一个新的Vector2D, 值为 (5.0, 5.0)
|
||||
```
|
||||
|
||||
这个例子实现两个向量 `(3.0,1.0)` 和 `(2.0,4.0)` 相加,得到向量 `(5.0,5.0)` 的过程。如下图示:
|
||||
这个例子实现两个向量 `(3.0,1.0)` 和 `(2.0,4.0)` 的相加,并得到新的向量 `(5.0,5.0)`。这个过程如下图示:
|
||||
|
||||

|
||||
|
||||
### 前置和后置运算符
|
||||
### 前缀和后缀运算符
|
||||
|
||||
上个例子演示了一个双目中置运算符的自定义实现,同样我们也可以玩标准单目运算符的实现。单目运算符只有一个操作数,在操作数之前就是前置的,如`-a`; 在操作数之后就是后置的,如`i++`。
|
||||
上个例子演示了一个双目中缀运算符的自定义实现。类与结构体也能提供标准单目运算符(`unary operators`)的实现。单目运算符只有一个操作目标。当运算符出现在操作目标之前时,它就是前缀(`prefix`)的(比如 `-a`),而当它出现在操作目标之后时,它就是后缀(`postfix`)的(比如 `i++`)。
|
||||
|
||||
实现一个前置或后置运算符时,在定义该运算符的时候于关键字`func`之前标注 `@prefix` 或 `@postfix` 属性。
|
||||
要实现前缀或者后缀运算符,需要在声明运算符函数的时候在 `func` 关键字之前指定 `prefix` 或者 `postfix` 限定符:
|
||||
|
||||
```swift
|
||||
@prefix func - (vector: Vector2D) -> Vector2D {
|
||||
prefix func - (vector: Vector2D) -> Vector2D {
|
||||
return Vector2D(x: -vector.x, y: -vector.y)
|
||||
}
|
||||
```
|
||||
|
||||
这段代码为`Vector2D`类型提供了单目减运算`-a`,`@prefix`属性表明这是个前置运算符。
|
||||
这段代码为 `Vector2D` 类型实现了单目减运算符(`-a`)。由于单目减运算符是前缀运算符,所以这个函数需要加上 `prefix` 限定符。
|
||||
|
||||
对于数值,单目减运算符可以把正数变负数,把负数变正数。对于`Vector2D`,单目减运算将其`x`和`y`都进进行单目减运算。
|
||||
对于简单数值,单目减运算符可以对它们的正负性进行改变。对于 `Vector2D` 来说,单目减运算将其 `x` 和 `y` 属性的正负性都进行了改变。
|
||||
|
||||
```swift
|
||||
let positive = Vector2D(x: 3.0, y: 4.0)
|
||||
let negative = -positive
|
||||
// negative 为 (-3.0, -4.0)
|
||||
// negative 是一个值为 (-3.0, -4.0) 的 Vector2D 实例
|
||||
|
||||
let alsoPositive = -negative
|
||||
// alsoPositive 为 (3.0, 4.0)
|
||||
// alsoPositive 是一个值为 (3.0, 4.0) 的 Vector2D 实例
|
||||
```
|
||||
|
||||
### 组合赋值运算符
|
||||
### 复合赋值运算符
|
||||
|
||||
组合赋值是其他运算符和赋值运算符一起执行的运算。如`+=`把加运算和赋值运算组合成一个操作。实现一个组合赋值符号需要使用`@assignment`属性,还需要把运算符的左参数设置成`inout`,因为这个参数会在运算符函数内直接修改它的值。
|
||||
复合赋值运算符(`Compound assignment operators`)将赋值运算符(`=`)与其它运算符进行结合。比如,将加法与赋值结合成加法赋值运算符(`+=`)。在实现的时候,需要把运算符的左参数设置成 `inout` 类型,因为这个参数的值会在运算符函数内直接被修改。
|
||||
|
||||
```swift
|
||||
@assignment func += (inout left: Vector2D, right: Vector2D) {
|
||||
func += (inout left: Vector2D, right: Vector2D) {
|
||||
left = left + right
|
||||
}
|
||||
```
|
||||
|
||||
因为加法运算在之前定义过了,这里无需重新定义。所以,加赋运算符函数使用已经存在的高级加法运算符函数来执行左值加右值的运算。
|
||||
因为加法运算在之前已经定义过了,所以在这里无需重新定义。在这里可以直接利用现有的加法运算符函数,用它来对左值和右值进行相加,并再次赋值给左值:
|
||||
|
||||
```swift
|
||||
var original = Vector2D(x: 1.0, y: 2.0)
|
||||
let vectorToAdd = Vector2D(x: 3.0, y: 4.0)
|
||||
original += vectorToAdd
|
||||
// original 现在为 (4.0, 6.0)
|
||||
// original 的值现在为 (4.0, 6.0)
|
||||
```
|
||||
|
||||
你可以将 `@assignment` 属性和 `@prefix` 或 `@postfix` 属性起来组合,实现一个`Vector2D`的前置运算符。
|
||||
还可以将赋值与 `prefix` 或 `postfix` 限定符结合起来,下面的代码为 `Vector2D` 实例实现了前缀自增运算符(`++a`):
|
||||
|
||||
```swift
|
||||
@prefix @assignment func ++ (inout vector: Vector2D) -> Vector2D {
|
||||
prefix func ++ (inout vector: Vector2D) -> Vector2D {
|
||||
vector += Vector2D(x: 1.0, y: 1.0)
|
||||
return vector
|
||||
}
|
||||
```
|
||||
|
||||
这个前置使用了已经定义好的高级加赋运算,将自己加上一个值为 `(1.0,1.0)` 的对象然后赋给自己,然后再将自己返回。
|
||||
这个前缀自增运算符使用了前面定义的加法赋值操作。它对 `Vector2D` 的 `x` 和 `y` 属性都进行了加 `1` 操作,再将结果返回:
|
||||
|
||||
```swift
|
||||
var toIncrement = Vector2D(x: 3.0, y: 4.0)
|
||||
let afterIncrement = ++toIncrement
|
||||
// toIncrement 现在是 (4.0, 5.0)
|
||||
// afterIncrement 现在也是 (4.0, 5.0)
|
||||
// toIncrement 的值现在为 (4.0, 5.0)
|
||||
// afterIncrement 的值同样为 (4.0, 5.0)
|
||||
```
|
||||
|
||||
> 注意:
|
||||
默认的赋值符(=)是不可重载的。只有组合赋值符可以重载。三目条件运算符 `a?b:c` 也是不可重载。
|
||||
> 不能对默认的赋值运算符(`=`)进行重载。只有组合赋值符可以被重载。同样地,也无法对三目条件运算符 `a ? b : c` 进行重载。
|
||||
|
||||
### 比较运算符
|
||||
### 等价运算符
|
||||
|
||||
Swift无所知道自定义类型是否相等或不等,因为等于或者不等于由你的代码说了算了。所以自定义的类和结构要使用比较符`==`或`!=`就需要重载。
|
||||
自定义的类和结构体没有对等价操作符(`equivalence operators`)进行默认实现,等价操作符通常被称为“相等”操作符(`==`)与“不等”操作符(`!=`)。对于自定义类型,Swift 无法判断其是否“相等”,因为“相等”的含义取决于这些自定义类型在你的代码中所扮演的角色。
|
||||
|
||||
定义相等运算符函数跟定义其他中置运算符雷同:
|
||||
为了使用等价操作符来对自定义的类型进行判等操作,需要为其提供自定义实现,实现的方法与其它中缀运算符一样:
|
||||
|
||||
```swift
|
||||
@infix func == (left: Vector2D, right: Vector2D) -> Bool {
|
||||
func == (left: Vector2D, right: Vector2D) -> Bool {
|
||||
return (left.x == right.x) && (left.y == right.y)
|
||||
}
|
||||
|
||||
@infix func != (left: Vector2D, right: Vector2D) -> Bool {
|
||||
func != (left: Vector2D, right: Vector2D) -> Bool {
|
||||
return !(left == right)
|
||||
}
|
||||
```
|
||||
|
||||
上述代码实现了相等运算符`==`来判断两个`Vector2D`对象是否有相等的值,相等的概念就是它们有相同的`x`值和相同的`y`值,我们就用这个逻辑来实现。接着使用`==`的结果实现了不相等运算符`!=`。
|
||||
上述代码实现了“相等”运算符(`==`)来判断两个 `Vector2D` 对象是否有相等。对于 `Vector2D` 类型来说,“相等”意味“两个实例的 `x`属性 和 `y` 属性都相等”,这也是代码中用来进行判等的逻辑。示例里同时也实现了“不等”操作符(`!=`),它简单地将“相等”操作符进行取反后返回。
|
||||
|
||||
现在我们可以使用这两个运算符来判断两个 `Vector2D` 对象是否相等。
|
||||
|
||||
@ -426,59 +416,61 @@ Swift无所知道自定义类型是否相等或不等,因为等于或者不等
|
||||
let twoThree = Vector2D(x: 2.0, y: 3.0)
|
||||
let anotherTwoThree = Vector2D(x: 2.0, y: 3.0)
|
||||
if twoThree == anotherTwoThree {
|
||||
println("这两个向量是相等的.")
|
||||
print("These two vectors are equivalent.")
|
||||
}
|
||||
// prints "这两个向量是相等的."
|
||||
// prints "These two vectors are equivalent."
|
||||
```
|
||||
|
||||
### 自定义运算符
|
||||
|
||||
标准的运算符不够玩,那你可以声明一些个性的运算符,但个性的运算符只能使用这些字符 `/ = - + * % < > ! & | ^ . ~`。
|
||||
除了实现标准运算符,在 Swift 当中还可以声明和实现自定义运算符(`custom operators`)。可以用来自定义运算符的字符列表请参考[操作符](../chapter3/02_Lexical_Structure.html#operators)
|
||||
|
||||
新的运算符声明需在全局域使用`operator`关键字声明,可以声明为前置,中置或后置的。
|
||||
新的运算符要在全局作用域内,使用 `operator` 关键字进行声明,同时还要指定 `prefix`、`infix` 或者 `postfix` 限定符:
|
||||
|
||||
```swift
|
||||
operator prefix +++ {}
|
||||
```
|
||||
|
||||
|
||||
这段代码定义了一个新的前置运算符叫`+++`,此前Swift并不存在这个运算符。此处为了演示,我们让`+++`对`Vector2D`对象的操作定义为 `双自增` 这样一个独有的操作,这个操作使用了之前定义的加赋运算实现了自已加上自己然后返回的运算。
|
||||
上面的代码定义了一个新的名为 `+++` 的前缀运算符。对于这个运算符,在 Swift 中并没有意义,因为我们针对 `Vector2D` 的实例来定义它的意义。对这个示例来讲,`+++` 被实现为“前缀双自增”运算符。它使用了前面定义的复合加法操作符来让矩阵对自身进行相加,从而让 `Vector2D` 实例的 `x` 属性和 `y`属性的值翻倍:
|
||||
|
||||
```swift
|
||||
@prefix @assignment func +++ (inout vector: Vector2D) -> Vector2D {
|
||||
prefix func +++ (inout vector: Vector2D) -> Vector2D {
|
||||
vector += vector
|
||||
return vector
|
||||
}
|
||||
```
|
||||
|
||||
`Vector2D` 的 `+++` 的实现和 `++` 的实现很接近, 唯一不同的是前者是加自己, 后者是加值为 `(1.0, 1.0)` 的向量.
|
||||
`Vector2D` 的 `+++` 的实现和 `++` 的实现很相似, 唯一不同的是前者对自身进行相加, 而后者是与另一个值为 `(1.0, 1.0)` 的向量相加.
|
||||
|
||||
```swift
|
||||
var toBeDoubled = Vector2D(x: 1.0, y: 4.0)
|
||||
let afterDoubling = +++toBeDoubled
|
||||
// toBeDoubled 现在是 (2.0, 8.0)
|
||||
// afterDoubling 现在也是 (2.0, 8.0)
|
||||
// toBeDoubled 现在的值为 (2.0, 8.0)
|
||||
// afterDoubling 现在的值也为 (2.0, 8.0)
|
||||
```
|
||||
|
||||
### 自定义中置运算符的优先级和结合性
|
||||
### 自定义中缀运算符的优先级和结合性
|
||||
|
||||
可以为自定义的中置运算符指定优先级和结合性。可以回头看看[优先级和结合性](#PrecedenceandAssociativity)解释这两个因素是如何影响多种中置运算符混合的表达式的计算的。
|
||||
自定义的中缀(`infix`)运算符也可以指定优先级(`precedence`)和结合性(`associativity`)。[优先级和结合性](#PrecedenceandAssociativity)中详细阐述了这两个特性是如何对中缀运算符的运算产生影响的。
|
||||
|
||||
结合性(associativity)的值可取的值有`left`,`right`和`none`。左结合运算符跟其他优先级相同的左结合运算符写在一起时,会跟左边的操作数结合。同理,右结合运算符会跟右边的操作数结合。而非结合运算符不能跟其他相同优先级的运算符写在一起。
|
||||
结合性(`associativity`)可取的值有` left`,`right` 和 `none`。当左结合运算符跟其他相同优先级的左结合运算符写在一起时,会跟左边的操作数进行结合。同理,当右结合运算符跟其他相同优先级的右结合运算符写在一起时,会跟右边的操作数进行结合。而非结合运算符不能跟其他相同优先级的运算符写在一起。
|
||||
|
||||
结合性(associativity)的值默认为`none`,优先级(precedence)默认为`100`。
|
||||
结合性(`associativity`)的默认值是 `none`,优先级(`precedence`)如果没有指定,则默认为 `100`。
|
||||
|
||||
以下例子定义了一个新的中置符`+-`,是左结合的`left`,优先级为`140`。
|
||||
以下例子定义了一个新的中缀运算符 `+-`,此操作符是左结合的,并且它的优先级为 `140`:
|
||||
|
||||
```swift
|
||||
operator infix +- { associativity left precedence 140 }
|
||||
infix operator +- { associativity left precedence 140 }
|
||||
func +- (left: Vector2D, right: Vector2D) -> Vector2D {
|
||||
return Vector2D(x: left.x + right.x, y: left.y - right.y)
|
||||
}
|
||||
let firstVector = Vector2D(x: 1.0, y: 2.0)
|
||||
let secondVector = Vector2D(x: 3.0, y: 4.0)
|
||||
let plusMinusVector = firstVector +- secondVector
|
||||
// plusMinusVector 此时的值为 (4.0, -2.0)
|
||||
// plusMinusVector 是一个 Vector2D 类型,并且它的值为 (4.0, -2.0)
|
||||
```
|
||||
|
||||
这个运算符把两个向量的`x`相加,把向量的`y`相减。因为他实际是属于加减运算,所以让它保持了和加法一样的结合性和优先级(`left`和`140`)。查阅完整的Swift默认结合性和优先级的设置,请移步[表达式](../chapter3/04_Expressions.html);
|
||||
这个运算符把两个向量的 `x` 值相加,同时用第一个向量的 `y` 值减去第二个向量的 `y` 值。因为它本质上是属于“加型”运算符,所以将它的结合性和优先级被设置为(`left` 和 `140`),这与 `+` 和 `-` 等默认的中缀加型操作符是相同的。完整的 Swift 操作符默认结合性与优先级请参考[表达式](../chapter3/04_Expressions.html)。
|
||||
|
||||
> 注意:
|
||||
> 当定义前缀与后缀操作符的时候,我们并没有指定优先级。然而,如果对同一个操作数同时使用前缀与后缀操作符,则后缀操作符会先被执行。
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
> 翻译:[dabing1022](https://github.com/dabing1022)
|
||||
> 校对:[numbbbbb](https://github.com/numbbbbb)
|
||||
> 校对:[numbbbbb](https://github.com/numbbbbb), [KYawn](https://github.com/KYawn)
|
||||
|
||||
|
||||
# 关于语言附注
|
||||
@ -11,28 +11,32 @@
|
||||
|
||||
本书的这一节描述了Swift编程语言的形式语法。这里描述的语法是为了帮助您更详细的了解该语言,而不是让您直接实现一个解析器或编译器。
|
||||
|
||||
|
||||
Swift语言相对小点,这是由于在Swift代码中几乎无处不在的许多常见的的类型,函数以及运算符都由Swift标准库来定义。虽然这些类型,函数和运算符不是Swift语言本身的一部分,但是它们被广泛用于这本书的讨论和代码范例。
|
||||
Swift语言相对小一点,这是由于在Swift代码中几乎所有常见的类型、函数以及运算符都已经在Swift标准库中定义了。虽然这些类型、函数和运算符并不是Swift语言自身的一部分,但是它们被广泛应用于本书的讨论和代码范例中。
|
||||
|
||||
<a name="how_to_read_the_grammar"></a>
|
||||
## 如何阅读语法
|
||||
|
||||
用来描述Swift编程语言形式语法的记法遵循下面几个约定:
|
||||
用来描述Swift编程语言形式语法的标记遵循下面几个约定:
|
||||
|
||||
- 箭头(→)用来标记语法产式,可以被理解为“可以包含”。
|
||||
- 句法范畴由*斜体*文字表示,并出现在一个语法产式规则两侧。
|
||||
- 义词和标点符号由粗体固定宽度的文本显示和只出现在一个语法产式规则的右边。
|
||||
- 箭头(→)用来标记语法产式,可以理解为“可以包含”。
|
||||
- *斜体*文字用来表示句法分类,并出现在一个语法产式规则两侧。
|
||||
- 义词和标点符号由粗体固定宽度的文本标记,而且只出现在一个语法产式规则的右侧。
|
||||
- 选择性的语法产式由竖线(|)分隔。当可选用的语法产式太多时,为了阅读方便,它们将被拆分为多行语法产式规则。
|
||||
- 在少数情况下,常规字体文字用来描述语法产式规则的右边。
|
||||
- 可选的句法范畴和文字用尾标`opt`来标记。
|
||||
- 少数情况下,常规字体文字用来描述语法产式规则的右边。
|
||||
- 可选的句法分类和文字用尾标`opt`来标记。
|
||||
|
||||
举个例子,getter-setter的语法块的定义如下:
|
||||
|
||||
> GRAMMAR OF A GETTER-SETTER BLOCK
|
||||
> *getter-setter-block* → { [*getter-clause*](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Declarations.html#//apple_ref/swift/grammar/getter-clause) [*setter-clause*](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Declarations.html#//apple_ref/swift/grammar/setter-clause)*opt* } | { [*setter-clause*](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Declarations.html#//apple_ref/swift/grammar/setter-clause) [*getter-clause*](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Declarations.html#//apple_ref/swift/grammar/getter-clause)}
|
||||
|
||||
这个定义表明,一个getter-setter方法块可以由一个getter子句后跟一个可选的setter子句构成,用大括号括起来,或者由一个setter子句后跟一个getter子句构成,用大括号括起来。上述的文法产生等价于下面的两个产生,明确阐明如何二中择一:
|
||||
这个定义表明,一个getter-setter方法块可以由一个getter子句后跟一个可选的setter子句构成,然后用大括号括起来,或者由一个setter子句后跟一个getter子句构成,然后用大括号括起来。下面的两个语法产式等价于上述的语法产式,并明确指出了如何取舍:
|
||||
|
||||
> GRAMMAR OF A GETTER-SETTER BLOCK
|
||||
> getter-setter-block → { [*getter-clause*](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Declarations.html#//apple_ref/swift/grammar/getter-clause) [*setter-clause*](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Declarations.html#//apple_ref/swift/grammar/setter-clause)*opt* }
|
||||
> getter-setter-block → { [*setter-clause*](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Declarations.html#//apple_ref/swift/grammar/setter-clause) [*getter-clause*](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Declarations.html#//apple_ref/swift/grammar/getter-clause)}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@ -12,76 +12,93 @@
|
||||
- [字面量(*Literals*)](#literals)
|
||||
- [运算符(*Operators*)](#operators)
|
||||
|
||||
Swift 的“词法结构(*lexical structure*)”描述了如何在该语言中用字符序列构建合法标记,组成该语言中最底层的代码块,并在之后的章节中用于描述语言的其他部分。
|
||||
Swift 的“词法结构(*lexical structure*)”描述了能构成该语言中合法标记(*tokens*)的字符序列。这些合法标记组成了语言中最底层的构建基块,并在之后的章节中用于描述语言的其他部分。
|
||||
|
||||
通常,标记在随后介绍的语法约束下,由 Swift 源文件的输入文本中提取可能的最长子串生成。这种方法称为“最长匹配项(*longest match*)”,或者“最大适合”(*maximal munch*)。
|
||||
通常情况下,标记是在随后将介绍的语法约束下,由 Swift 源文件的输入文本中提取可能的最长子串生成。这种方法称为“最长匹配项(*longest match*)”,或者“最大适合”(*maximal munch*)。
|
||||
|
||||
<a name="whitespace_and_comments"></a>
|
||||
<a id="whitespace_and_comments"></a>
|
||||
## 空白与注释
|
||||
|
||||
空白(*whitespace*)有两个用途:分隔源文件中的标记和区分运算符属于前缀还是后缀,(参见 [运算符](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/LexicalStructure.html#//apple_ref/doc/uid/TP40014097-CH30-XID_871))在其他情况下则会被忽略。以下的字符会被当作空白:空格(*space*)(U+0020)、换行符(*line feed*)(U+000A)、回车符(*carriage return*)(U+000D)、水平 tab(*horizontal tab*)(U+0009)、垂直 tab(*vertical tab*)(U+000B)、换页符(*form feed*)(U+000C)以及空(*null*)(U+0000)。
|
||||
空白(*whitespace*)有两个用途:分隔源文件中的标记和帮助区分运算符属于前缀还是后缀(参见 [运算符](#operators)),在其他情况下则会被忽略。以下的字符会被当作空白:空格(*space*)(U+0020)、换行符(*line feed*)(U+000A)、回车符(*carriage return*)(U+000D)、水平制表符(*horizontal tab*)(U+0009)、垂直制表符(*vertical tab*)(U+000B)、换页符(*form feed*)(U+000C)以及空(*null*)(U+0000)。
|
||||
|
||||
注释(*comments*)被编译器当作空白处理。单行注释由 `//` 开始直到该行结束。多行注释由 `/*` 开始,以 `*/` 结束。可以嵌套注释,但注意注释标记必须匹配。
|
||||
注释(*comments*)被编译器当作空白处理。单行注释由 `//` 开始直至遇到换行符(*line feed*)(U+000A)或者回车符(*carriage return*)(U+000D)。多行注释由 `/*` 开始,以 `*/` 结束。注释允许嵌套,但注释标记必须匹配。
|
||||
|
||||
<a name="identifiers"></a>
|
||||
<a id="identifiers"></a>
|
||||
## 标识符
|
||||
|
||||
标识符(*identifiers*)可以由以下的字符开始:大写或小写的字母 `A` 到 `Z`、下划线 `_`、基本多语言面(*Basic Multilingual Plane*)中的 Unicode 非组合字符以及基本多语言面以外的非专用区(*Private Use Area*)字符。首字符之后,标识符允许使用数字和 Unicode 字符组合。
|
||||
标识符(*identifiers*)可以由以下的字符开始:大写或小写的字母 `A` 到 `Z`、下划线 `_`、基本多文种平面(*Basic Multilingual Plane*)中的 Unicode 非组合字符以及基本多文种平面以外的非专用区(*Private Use Area*)字符。首字符之后,允许使用数字和 Unicode 字符组合。
|
||||
|
||||
使用保留字(*reserved word*)作为标识符,需要在其前后增加反引号 <code>\`</code>。例如,<code>class</code> 不是合法的标识符,但可以使用 <code>\`class\`</code>。反引号不属于标识符的一部分,<code>\`x\`</code> 和 `x` 表示同一标识符。
|
||||
使用保留字(*reserved word*)作为标识符,需要在其前后增加反引号 `` `。例如,`class` 不是合法的标识符,但可以使用 <code>\`class\`</code>。反引号不属于标识符的一部分,<code>\`x\`</code> 和 `x` 表示同一标识符。
|
||||
|
||||
闭包(*closure*)中如果没有明确指定参数名称,参数将被隐式命名为 <code>$0</code>、<code>$1</code>、<code>$2</code>... 这些命名在闭包作用域内是合法的标识符。
|
||||
闭包(*closure*)中如果没有明确指定参数名称,参数将被隐式命名为 `$0`、`$1`、`$2`等等。 这些命名在闭包作用域范围内是合法的标识符。
|
||||
|
||||
> 标识符语法
|
||||
> *标识符* → [*标识符头(Head)*](LexicalStructure.html#identifier_head) [*标识符字符列表*](LexicalStructure.html#identifier_characters) _可选_
|
||||
> *标识符* → **`** [*标识符头(Head)*](LexicalStructure.html#identifier_head) [*标识符字符列表*](LexicalStructure.html#identifier_characters) _可选_ **`**
|
||||
> *标识符* → [*隐式参数名*](LexicalStructure.html#implicit_parameter_name)
|
||||
> *标识符列表* → [*标识符*](LexicalStructure.html#identifier) | [*标识符*](LexicalStructure.html#identifier) **,** [*标识符列表*](LexicalStructure.html#identifier_list)
|
||||
> *标识符头(Head)* → Upper- or lowercase letter A through Z
|
||||
> *标识符头(Head)* → U+00A8, U+00AA, U+00AD, U+00AF, U+00B2–U+00B5, or U+00B7–U+00BA
|
||||
> *标识符头(Head)* → U+00BC–U+00BE, U+00C0–U+00D6, U+00D8–U+00F6, or U+00F8–U+00FF
|
||||
> *标识符头(Head)* → U+0100–U+02FF, U+0370–U+167F, U+1681–U+180D, or U+180F–U+1DBF
|
||||
> *标识符头(Head)* → U+1E00–U+1FFF
|
||||
> *标识符头(Head)* → U+200B–U+200D, U+202A–U+202E, U+203F–U+2040, U+2054, or U+2060–U+206F
|
||||
> *标识符头(Head)* → U+2070–U+20CF, U+2100–U+218F, U+2460–U+24FF, or U+2776–U+2793
|
||||
> *标识符头(Head)* → U+2C00–U+2DFF or U+2E80–U+2FFF
|
||||
> *标识符头(Head)* → U+3004–U+3007, U+3021–U+302F, U+3031–U+303F, or U+3040–U+D7FF
|
||||
> *标识符头(Head)* → U+F900–U+FD3D, U+FD40–U+FDCF, U+FDF0–U+FE1F, or U+FE30–U+FE44
|
||||
> *标识符头(Head)* → U+FE47–U+FFFD
|
||||
> *标识符头(Head)* → U+10000–U+1FFFD, U+20000–U+2FFFD, U+30000–U+3FFFD, or U+40000–U+4FFFD
|
||||
> *标识符头(Head)* → U+50000–U+5FFFD, U+60000–U+6FFFD, U+70000–U+7FFFD, or U+80000–U+8FFFD
|
||||
> *标识符头(Head)* → U+90000–U+9FFFD, U+A0000–U+AFFFD, U+B0000–U+BFFFD, or U+C0000–U+CFFFD
|
||||
> *标识符头(Head)* → U+D0000–U+DFFFD or U+E0000–U+EFFFD
|
||||
> *标识符字符* → 数值 0 到 9
|
||||
<a id="identifier"></a>
|
||||
> *标识符* → [*头部标识符*](#identifier_head) [*标识符字符组*](#identifier_characters)<sub>可选</sub>
|
||||
> *标识符* → \`[*头部标识符*](#identifier_head) [*标识符字符组*](#identifier_characters)<sub>可选</sub>\`
|
||||
> *标识符* → [*隐式参数名*](#implicit_parameter_name)
|
||||
> *标识符列表* → [*标识符*](#identifier) | [*标识符*](#identifier) **,** [*标识符列表*](#identifier_list)
|
||||
<a id="identifier_head"></a>
|
||||
> *头部标识符* → 大写或小写字母 A - Z
|
||||
> *头部标识符* → U+00A8, U+00AA, U+00AD, U+00AF, U+00B2–U+00B5, or U+00B7–U+00BA
|
||||
> *头部标识符* → U+00BC–U+00BE, U+00C0–U+00D6, U+00D8–U+00F6, or U+00F8–U+00FF
|
||||
> *头部标识符* → U+0100–U+02FF, U+0370–U+167F, U+1681–U+180D, or U+180F–U+1DBF
|
||||
> *头部标识符* → U+1E00–U+1FFF
|
||||
> *头部标识符* → U+200B–U+200D, U+202A–U+202E, U+203F–U+2040, U+2054, or U+2060–U+206F
|
||||
> *头部标识符* → U+2070–U+20CF, U+2100–U+218F, U+2460–U+24FF, or U+2776–U+2793
|
||||
> *头部标识符* → U+2C00–U+2DFF or U+2E80–U+2FFF
|
||||
> *头部标识符* → U+3004–U+3007, U+3021–U+302F, U+3031–U+303F, or U+3040–U+D7FF
|
||||
> *头部标识符* → U+F900–U+FD3D, U+FD40–U+FDCF, U+FDF0–U+FE1F, or U+FE30–U+FE44
|
||||
> *头部标识符* → U+FE47–U+FFFD
|
||||
> *头部标识符* → U+10000–U+1FFFD, U+20000–U+2FFFD, U+30000–U+3FFFD, or U+40000–U+4FFFD
|
||||
> *头部标识符* → U+50000–U+5FFFD, U+60000–U+6FFFD, U+70000–U+7FFFD, or U+80000–U+8FFFD
|
||||
> *头部标识符* → U+90000–U+9FFFD, U+A0000–U+AFFFD, U+B0000–U+BFFFD, or U+C0000–U+CFFFD
|
||||
> *头部标识符* → U+D0000–U+DFFFD or U+E0000–U+EFFFD
|
||||
> *标识符字符* → 数值 0 - 9
|
||||
> *标识符字符* → U+0300–U+036F, U+1DC0–U+1DFF, U+20D0–U+20FF, or U+FE20–U+FE2F
|
||||
> *标识符字符* → [*标识符头(Head)*](LexicalStructure.html#identifier_head)
|
||||
> *标识符字符列表* → [*标识符字符*](LexicalStructure.html#identifier_character) [*标识符字符列表*](LexicalStructure.html#identifier_characters) _可选_
|
||||
> *隐式参数名* → **$** [*十进制数字列表*](LexicalStructure.html#decimal_digits)
|
||||
> *标识符字符* → [*头部标识符*](#identifier_head)
|
||||
<a id="identifier_characters"></a>
|
||||
> *标识符字符组* → [*标识符字符*](#identifier_character) [*标识符字符列表*](#identifier_characters)<sub>可选</sub>
|
||||
<a id="implicit_parameter_name"></a>
|
||||
> *隐式参数名* → **$** [*十进制数字列表*](#decimal_digits)
|
||||
|
||||
<a name="keywords"></a>
|
||||
## 关键字
|
||||
<a id="keywords"></a>
|
||||
## 关键字和符号
|
||||
|
||||
被保留的关键字(*keywords*)不允许用作标识符,除非被反引号转义,参见 [标识符](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/LexicalStructure.html#//apple_ref/doc/uid/TP40014097-CH30-XID_796)。
|
||||
下面这些被保留的关键字(*keywords*)不允许用作标识符,除非被反引号转义,具体描述请参考 [标识符](#identifiers)。
|
||||
|
||||
* **用作声明的关键字:** *class*、*deinit*、*enum*、*extension*、*func*、*import*、*init*、*let*、*protocol*、*static*、*struct*、*subscript*、*typealias*、*var*
|
||||
* **用作语句的关键字:** *break*、*case*、*continue*、*default*、*do*、*else*、*fallthrough*、*if*、*in*、*for*、*return*、*switch*、*where*、*while*
|
||||
* **用作表达和类型的关键字:** *as*、*dynamicType*、*is*、*new*、*super*、*self*、*Self*、*Type*、*\_\_COLUMN\_\_*、*\_\_FILE\_\_*、*\_\_FUNCTION\_\_*、*\_\_LINE\_\_*
|
||||
* **特定上下文中被保留的关键字:** *associativity*、*didSet*、*get*、*infix*、*inout*、*left*、*mutating*、*none*、*nonmutating*、*operator*、*override*、*postfix*、
|
||||
*precedence*、*prefix*、*right*、*set*、*unowned*、*unowned(safe)*、*unowned(unsafe)*、*weak*、*willSet*,这些关键字在特定上下文之外可以被用于标识符。
|
||||
* **用在声明中的关键字:** *class*、*deinit*、*enum*、*extension*、*func*、*import*、*init*、*let*、*protocol*、*static*、*struct*、*subscript*、*typealias*、*var*
|
||||
* **用在语句中的关键字:** *break*、*case*、*continue*、*default*、*do*、*else*、*fallthrough*、*if*、*in*、*for*、*return*、*switch*、*where*、*while*
|
||||
* **用在表达式和类型中的关键字:** *as*、*dynamicType*、*is*、*new*、*super*、*self*、*Self*、*Type*、*\_\_COLUMN\_\_*、*\_\_FILE\_\_*、*\_\_FUNCTION\_\_*、*\_\_LINE\_\_*
|
||||
* **用在模式中的关键字:** *\_*
|
||||
* **特定上下文中被保留的关键字:** *associativity*、*didSet*、*get*、*infix*、*inout*、*left*、*mutating*、*none*、*nonmutating*、*operator*、*override*、*postfix*、*precedence*、*prefix*、*right*、*set*、*unowned*、*unowned(safe)*、*unowned(unsafe)*、*weak*、*willSet*,这些关键字在特定上下文之外可以被用于标识符。
|
||||
|
||||
<a name="literals"></a>
|
||||
以下标记被当作保留符号,不能用于自定义操作符:`(`、`)`、`{`、`}`、`[`、`]`、`.`、`,`、`:`、`;`、`=`、`@`、`#`、`&(作为前缀操作符)`、`->`、`` `、`?` 和 `!(作为后缀操作符)`。
|
||||
|
||||
<a id="literals"></a>
|
||||
## 字面量
|
||||
|
||||
字面值表示整型、浮点型数字或文本类型的值,举例如下:
|
||||
字面量是用来表示源码中某种特定类型的值,比如一个数字或字符串。
|
||||
|
||||
下面是字面量的一些示例:
|
||||
|
||||
```swift
|
||||
42 // 整型字面量
|
||||
3.14159 // 浮点型字面量
|
||||
"Hello, world!" // 文本型字面量
|
||||
"Hello, world!" // 字符串型字面量
|
||||
true // 布尔型字面量
|
||||
```
|
||||
|
||||
字面量本身并不包含类型信息。事实上,一个字面量会被解析为拥有无限的精度,然后 Swift 的类型推导会尝试去推导出这个字面量的类型。比如,在 `let x: Int8 = 42` 这个声明中,Swift 使用了显式类型标注(`: Int8`)来推导出 `42` 这个整型字面量的类型是 `Int8`。如果没有可用的类型信息, Swift 则会从标准库中定义的字面量类型中推导出一个默认的类型。整型字面量的默认类型是 `Int`,浮点型字面量的默认类型是 `Double`,字符串型字面量的默认类型是 `String`,布尔型字面量的默认类型是 `Bool`。比如,在 `let str = "Hello, world"` 这个声明中,字符串 `"Hello, world"`的默认推导类型就是 `String`。
|
||||
|
||||
当为一个字面量值指定了类型标注的时候,这个注解的类型必须能通过这个字面量值实例化后得到。也就是说,这个类型必须遵守这些 Swift 标准库协议中的一个:整型字面量的`IntegerLiteralConvertible`协议、符点型字面量的`FloatingPointLiteralConvertible`协议、字符串字面量的`StringLiteralConvertible`协议以及布尔型字面量的`BooleanLiteralConvertible`协议。比如,`Int8` 遵守了 `IntegerLiteralConvertible`协议,因此它能在 `let x: Int8 = 42` 这个声明中作为整型字面量 `42` 的类型标注。
|
||||
|
||||
> 字面量语法
|
||||
> *字面量* → [*整型字面量*](LexicalStructure.html#integer_literal) | [*浮点数字面量*](LexicalStructure.html#floating_point_literal) | [*字符串字面量*](LexicalStructure.html#string_literal)
|
||||
> *字面量* → [*数字型字面量*](#numeric_literal) | [*字符串型字面量*](#string_literal) | [*布尔型字面量*](#boolean_literal) | [*nil型字面量*](#nil_literal)
|
||||
<a id="numeric_literal"></a>
|
||||
> *数字型字面量* → -<sub>可选</sub>[*整型字面量*](#integer_literal) | -<sub>可选</sub>[*符点型字面量*](#floating_point_literal)
|
||||
> *布尔型字面量* → **true** | **false**
|
||||
> *nil型字面量* → **nil**
|
||||
|
||||
### 整型字面量
|
||||
|
||||
@ -89,39 +106,38 @@ Swift 的“词法结构(*lexical structure*)”描述了如何在该语言
|
||||
|
||||
十进制字面量包含数字 `0` 至 `9`。二进制字面量只包含 `0` 或 `1`,八进制字面量包含数字 `0` 至 `7`,十六进制字面量包含数字 `0` 至 `9` 以及字母 `A` 至 `F` (大小写均可)。
|
||||
|
||||
负整数的字面量在数字前加减号 `-`,比如 `-42`。
|
||||
负整数的字面量在整型字面量前加减号 `-`,比如 `-42`。
|
||||
|
||||
允许使用下划线 `_` 来增加数字的可读性,下划线不会影响字面量的值。整型字面量也可以在数字前加 `0`,同样不会影响字面量的值。
|
||||
整型字面面可以使用下划线 `_` 来增加数字的可读性,下划线会被系统忽略,因此不会影响字面量的值。同样地,也可以在数字前加 `0`,并不会影响字面量的值。
|
||||
|
||||
```swift
|
||||
1000_000 // 等于 1000000
|
||||
005 // 等于 5
|
||||
```
|
||||
|
||||
除非特殊指定,整型字面量的默认类型为 Swift 标准库类型中的 `Int`。Swift 标准库还定义了其他不同长度以及是否带符号的整数类型,请参考 [整数类型](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/TheBasics.html#//apple_ref/doc/uid/TP40014097-CH5-XID_411)。
|
||||
除非特别指定,整型字面量的默认推导类型为 Swift 标准库类型中的 `Int`。Swift 标准库还定义了其他不同长度以及是否带符号的整数类型,请参考 [整数类型](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/TheBasics.html#//apple_ref/doc/uid/TP40014097-CH5-ID323)。
|
||||
|
||||
> 整型字面量语法
|
||||
> *整型字面量* → [*二进制字面量*](LexicalStructure.html#binary_literal)
|
||||
> *整型字面量* → [*八进制字面量*](LexicalStructure.html#octal_literal)
|
||||
> *整型字面量* → [*十进制字面量*](LexicalStructure.html#decimal_literal)
|
||||
> *整型字面量* → [*十六进制字面量*](LexicalStructure.html#hexadecimal_literal)
|
||||
> *二进制字面量* → **0b** [*二进制数字*](LexicalStructure.html#binary_digit) [*二进制字面量字符列表*](LexicalStructure.html#binary_literal_characters) _可选_
|
||||
> *整型字面量* → [*二进制字面量*](#binary_literal)
|
||||
> *整型字面量* → [*八进制字面量*](#octal_literal)
|
||||
> *整型字面量* → [*十进制字面量*](#decimal_literal)
|
||||
> *整型字面量* → [*十六进制字面量*](#hexadecimal_literal)
|
||||
<a id="binary_literal"></a>
|
||||
> *二进制字面量* → **0b** [*二进制数字*](#binary_digit) [*二进制字面量字符组*](#binary_literal_characters)<sub>可选</sub>
|
||||
> *二进制数字* → 数值 0 到 1
|
||||
> *二进制字面量字符* → [*二进制数字*](LexicalStructure.html#binary_digit) | **_**
|
||||
> *二进制字面量字符列表* → [*二进制字面量字符*](LexicalStructure.html#binary_literal_character) [*二进制字面量字符列表*](LexicalStructure.html#binary_literal_characters) _可选_
|
||||
> *八进制字面量* → **0o** [*八进字数字*](LexicalStructure.html#octal_digit) [*八进制字符列表*](LexicalStructure.html#octal_literal_characters) _可选_
|
||||
> *二进制字面量字符* → [*二进制数字*](#binary_digit) | _
|
||||
> *二进制字面量字符组* → [*二进制字面量字符*](#binary_literal_character) [*二进制字面量字符组*](#binary_literal_characters)<sub>可选</sub>
|
||||
<a id="octal_literal"></a>
|
||||
> *八进制字面量* → **0o** [*八进字数字*](#octal_digit) [*八进制字符列表*](#octal_literal_characters)<sub>可选</sub>
|
||||
> *八进字数字* → 数值 0 到 7
|
||||
> *八进制字符* → [*八进字数字*](LexicalStructure.html#octal_digit) | **_**
|
||||
> *八进制字符列表* → [*八进制字符*](LexicalStructure.html#octal_literal_character) [*八进制字符列表*](LexicalStructure.html#octal_literal_characters) _可选_
|
||||
> *十进制字面量* → [*十进制数字*](LexicalStructure.html#decimal_digit) [*十进制字符列表*](LexicalStructure.html#decimal_literal_characters) _可选_
|
||||
> *八进制字符* → [*八进字数字*](#octal_digit) | _
|
||||
> *八进制字符组* → [*八进制字符*](#octal_literal_character) [*八进制字符列表*](#octal_literal_characters)<sub>可选</sub>
|
||||
<a id="decimal_literal"></a>
|
||||
> *十进制字面量* → [*十进制数字*](#decimal_digit) [*十进制字符组*](#decimal_literal_characters)<sub>可选</sub>
|
||||
> *十进制数字* → 数值 0 到 9
|
||||
> *十进制数字列表* → [*十进制数字*](LexicalStructure.html#decimal_digit) [*十进制数字列表*](LexicalStructure.html#decimal_digits) _可选_
|
||||
> *十进制字符* → [*十进制数字*](LexicalStructure.html#decimal_digit) | **_**
|
||||
> *十进制字符列表* → [*十进制字符*](LexicalStructure.html#decimal_literal_character) [*十进制字符列表*](LexicalStructure.html#decimal_literal_characters) _可选_
|
||||
> *十六进制字面量* → **0x** [*十六进制数字*](LexicalStructure.html#hexadecimal_digit) [*十六进制字面量字符列表*](LexicalStructure.html#hexadecimal_literal_characters) _可选_
|
||||
> *十六进制数字* → 数值 0 到 9, a through f, or A through F
|
||||
> *十六进制字符* → [*十六进制数字*](LexicalStructure.html#hexadecimal_digit) | **_**
|
||||
> *十六进制字面量字符列表* → [*十六进制字符*](LexicalStructure.html#hexadecimal_literal_character) [*十六进制字面量字符列表*](LexicalStructure.html#hexadecimal_literal_characters) _可选_
|
||||
> *十进制数字列表* → [*十进制数字*](#decimal_digit) [*十进制数字列表*](#decimal_digits)<sub>可选</sub>
|
||||
> *十进制字符* → [*十进制数字*](#decimal_digit) | _
|
||||
> *十进制字符列表* → [*十进制字符*](#decimal_literal_character) [*十进制字符列表*](#decimal_literal_characters)<sub>可选</sub>
|
||||
<a id="hexadecimal_literal"></a>
|
||||
> *十六进制字面量* → **0x** [*十六进制数字*](#hexadecimal_digit) [*十六进制字面量字符列表*](#hexadecimal_literal_characters)<sub>可选</sub>
|
||||
> *十六进制数字* → 数值 0 到 9, 字母 a 到 f, 或 A 到 F
|
||||
> *十六进制字符* → [*十六进制数字*](#hexadecimal_digit) | _
|
||||
> *十六进制字面量字符列表* → [*十六进制字符*](#hexadecimal_literal_character) [*十六进制字面量字符列表*](#hexadecimal_literal_characters)<sub>可选</sub>
|
||||
|
||||
### 浮点型字面量
|
||||
|
||||
@ -129,110 +145,135 @@ Swift 的“词法结构(*lexical structure*)”描述了如何在该语言
|
||||
|
||||
浮点型字面量默认用十进制表示(无前缀),也可以用十六进制表示(加前缀 `0x`)。
|
||||
|
||||
十进制浮点型字面量(*decimal floating-point literals*)由十进制数字串后跟小数部分或指数部分(或两者皆有)组成。十进制小数部分由小数点 `.` 后跟十进制数字串组成。指数部分由大写或小写字母 `e` 后跟十进制数字串组成,这串数字表示 `e` 之前的数量乘以 10 的几次方。例如:`1.25e2` 表示 `1.25 ⨉ 10^2`,也就是 `125.0`;同样,`1.25e-2` 表示 `1.25 ⨉ 10^-2`,也就是 `0.0125`。
|
||||
十进制浮点型字面量(*decimal floating-point literals*)由十进制数字串后跟小数部分或指数部分(或两者皆有)组成。十进制小数部分由小数点 `.` 后跟十进制数字串组成。指数部分由大写或小写字母 `e` 为前缀后跟十进制数字串组成,这串数字表示 `e` 之前的数量乘以 10 的几次方。例如:`1.25e2` 表示 `1.25 ⨉ 10^2`,也就是 `125.0`;同样,`1.25e-2` 表示 `1.25 ⨉ 10^-2`,也就是 `0.0125`。
|
||||
|
||||
十六进制浮点型字面量(*hexadecimal floating-point literals*)由前缀 `0x` 后跟可选的十六进制小数部分以及十六进制指数部分组成。十六进制小数部分由小数点后跟十六进制数字串组成。指数部分由大写或小写字母 `p` 后跟十进制数字串组成,这串数字表示 `p` 之前的数量乘以 2 的几次方。例如:`0xFp2` 表示 `15 ⨉ 2^2`,也就是 `60`;同样,`0xFp-2` 表示 `15 ⨉ 2^-2`,也就是 `3.75`。
|
||||
十六进制浮点型字面量(*hexadecimal floating-point literals*)由前缀 `0x` 后跟可选的十六进制小数部分以及十六进制指数部分组成。十六进制小数部分由小数点后跟十六进制数字串组成。指数部分由大写或小写字母 `p` 为前缀后跟十进制数字串组成,这串数字表示 `p` 之前的数量乘以 2 的几次方。例如:`0xFp2` 表示 `15 ⨉ 2^2`,也就是 `60`;同样,`0xFp-2` 表示 `15 ⨉ 2^-2`,也就是 `3.75`。
|
||||
|
||||
与整型字面量不同,负的浮点型字面量由一元运算符减号 `-` 和浮点型字面量组成,例如 `-42.0`。这代表一个表达式,而不是一个浮点整型字面量。
|
||||
负的浮点型字面量由一元运算符减号 `-` 和浮点型字面量组成,例如 `-42.5`。
|
||||
|
||||
允许使用下划线 `_` 来增强可读性,下划线不会影响字面量的值。浮点型字面量也可以在数字前加 `0`,同样不会影响字面量的值。
|
||||
浮点型字面量允许使用下划线 `_` 来增强数字的可读性,下划线会被系统忽略,因此不会影响字面量的值。同样地,也可以在数字前加 `0`,并不会影响字面量的值。
|
||||
|
||||
```swift
|
||||
10_000.56 // 等于 10000.56
|
||||
005000.76 // 等于 5000.76
|
||||
```
|
||||
|
||||
除非特殊指定,浮点型字面量的默认类型为 Swift 标准库类型中的 `Double`,表示64位浮点数。Swift 标准库也定义 `Float` 类型,表示32位浮点数。
|
||||
除非特别指定,浮点型字面量的默认推导类型为 Swift 标准库类型中的 `Double`,表示64位浮点数。Swift 标准库也定义了 `Float` 类型,表示32位浮点数。
|
||||
|
||||
> 浮点型字面量语法
|
||||
> *浮点数字面量* → [*十进制字面量*](LexicalStructure.html#decimal_literal) [*十进制分数*](LexicalStructure.html#decimal_fraction) _可选_ [*十进制指数*](LexicalStructure.html#decimal_exponent) _可选_
|
||||
> *浮点数字面量* → [*十六进制字面量*](LexicalStructure.html#hexadecimal_literal) [*十六进制分数*](LexicalStructure.html#hexadecimal_fraction) _可选_ [*十六进制指数*](LexicalStructure.html#hexadecimal_exponent)
|
||||
> *十进制分数* → **.** [*十进制字面量*](LexicalStructure.html#decimal_literal)
|
||||
> *十进制指数* → [*浮点数e*](LexicalStructure.html#floating_point_e) [*正负号*](LexicalStructure.html#sign) _可选_ [*十进制字面量*](LexicalStructure.html#decimal_literal)
|
||||
> *十六进制分数* → **.** [*十六进制字面量*](LexicalStructure.html#hexadecimal_literal) _可选_
|
||||
> *十六进制指数* → [*浮点数p*](LexicalStructure.html#floating_point_p) [*正负号*](LexicalStructure.html#sign) _可选_ [*十六进制字面量*](LexicalStructure.html#hexadecimal_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_literal)
|
||||
> *十进制指数* → [*浮点数e*](#floating_point_e) [*正负号*](#sign)<sub>可选</sub> [*十进制字面量*](#decimal_literal)
|
||||
<a id="hexadecimal_literal"></a>
|
||||
> *十六进制分数* → **.** [*十六进制数字*](#hexadecimal_digit) [*十六进制字面量字符列表*](#hexadecimal_literal_characters)<sub>可选</sub>
|
||||
> *十六进制指数* → [*浮点数p*](#floating_point_p) [*正负号*](#sign)<sub>可选</sub> [*十进制字面量*](#decimal_literal)
|
||||
<a id="floating_point_e"></a>
|
||||
> *浮点数e* → **e** | **E**
|
||||
> *浮点数p* → **p** | **P**
|
||||
> *正负号* → **+** | **-**
|
||||
|
||||
### 文本型字面量
|
||||
|
||||
文本型字面量(*string literal*)由双引号中的字符串组成,形式如下:
|
||||
### 字符串型字面量
|
||||
|
||||
```swift
|
||||
字符串型字面量(*string literal*)由被包在双引号中的一串字符组成,形式如下:
|
||||
|
||||
```
|
||||
"characters"
|
||||
```
|
||||
|
||||
文本型字面量中不能包含未转义的双引号 `"`、未转义的反斜线`\`、回车符(*carriage return*)或换行符(*line feed*)。
|
||||
字符串型字面量中不能包含未转义的双引号 (`"`)、未转义的反斜线(`\`)、回车符(*carriage return*)或换行符(*line feed*)。
|
||||
|
||||
可以在文本型字面量中使用的转义特殊符号如下:
|
||||
可以在字符串字面量中使用的转义特殊符号如下:
|
||||
|
||||
* 空字符(Null Character)`\0`
|
||||
* 反斜线(Backslash)`\\`
|
||||
* 水平 Tab (Horizontal Tab)`\t`
|
||||
* 水平制表符(Horizontal Tab)`\t`
|
||||
* 换行符(Line Feed)`\n`
|
||||
* 回车符(Carriage Return)`\r`
|
||||
* 双引号(Double Quote)`\"`
|
||||
* 单引号(Single Quote)`\'`
|
||||
* Unicode标量 `\u{n}`,n为一到八位的十六进制数字
|
||||
|
||||
字符也可以用以下方式表示:
|
||||
字符串字面量允许在反斜杠小括号 `\()` 中插入表达式的值。插入表达式(*interpolated expression*)不能包含未转义的双引号 `"`、未转义的反斜线 `\`、回车符或者换行符。表达式结果的类型必须在 *String* 类中有对应的初始化方法。
|
||||
|
||||
* `\x` 后跟两位十六进制数字
|
||||
* `\u` 后跟四位十六进制数字
|
||||
* `\U` 后跟八位十六进制数字
|
||||
例如,以下所有字符串字面量的值都是相同的:
|
||||
|
||||
后跟的数字表示一个 Unicode 码点。
|
||||
|
||||
文本型字面量允许在反斜线小括号 `\()` 中插入表达式的值。插入表达式(*interpolated expression*)不能包含未转义的双引号 `"`、反斜线 `\`、回车符或者换行符。表达式值的类型必须在 *String* 类中有对应的初始化方法。
|
||||
|
||||
例如,以下所有文本型字面量的值相同:
|
||||
|
||||
```swift
|
||||
```
|
||||
"1 2 3"
|
||||
"1 2 \(3)"
|
||||
"1 2 \(1 + 2)"
|
||||
var x = 3; "1 2 \(x)"
|
||||
let x = 3; "1 2 \(x)"
|
||||
```
|
||||
|
||||
文本型字面量的默认类型为 `String`。组成字符串的字符类型为 `Character`。更多有关 `String` 和 `Character` 的信息请参照 [字符串和字符](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/StringsAndCharacters.html#//apple_ref/doc/uid/TP40014097-CH7-XID_368)。
|
||||
字符串字面量的默认推导类型为 `String`。组成字符串的字符默认推导类型为 `Character`。更多有关 `String` 和 `Character` 的信息请参照 [字符串和字符](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/StringsAndCharacters.html#//apple_ref/doc/uid/TP40014097-CH7-XID_368)。
|
||||
|
||||
> 字符型字面量语法
|
||||
> *字符串字面量* → **"** [*引用文本*](LexicalStructure.html#quoted_text) **"**
|
||||
> *引用文本* → [*引用文本条目*](LexicalStructure.html#quoted_text_item) [*引用文本*](LexicalStructure.html#quoted_text) _可选_
|
||||
> *引用文本条目* → [*转义字符*](LexicalStructure.html#escaped_character)
|
||||
> *引用文本条目* → **\(** [*表达式*](..\chapter3\04_Expressions.html#expression) **)**
|
||||
> *引用文本条目* → 除了", \, U+000A, or U+000D的所有Unicode的字符
|
||||
> *字符串字面量* → **"** [*引用文本*](#quoted_text)<sub>可选</sub> **"**
|
||||
<a id="quoted_text"></a>
|
||||
> *引用文本* → [*引用文本条目*](#quoted_text_item) [*引用文本*](#quoted_text) <sub>可选</sub>
|
||||
> *引用文本条目* → [*转义字符*](#escaped_character)
|
||||
> *引用文本条目* → **\(** [*表达式*](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Expressions.html#//apple_ref/doc/uid/TP40014097-CH32-ID383) **)**
|
||||
> *引用文本条目* → **除了", \, U+000A, 或者 U+000D的所有Unicode的字符**
|
||||
> *转义字符* → **\0** | **\\** | **\t** | **\n** | **\r** | **\"** | **\'**
|
||||
> *转义字符* → **\x** [*十六进制数字*](LexicalStructure.html#hexadecimal_digit) [*十六进制数字*](LexicalStructure.html#hexadecimal_digit)
|
||||
> *转义字符* → **\u** [*十六进制数字*](LexicalStructure.html#hexadecimal_digit) [*十六进制数字*](LexicalStructure.html#hexadecimal_digit) [*十六进制数字*](LexicalStructure.html#hexadecimal_digit) [*十六进制数字*](LexicalStructure.html#hexadecimal_digit)
|
||||
> *转义字符* → **\U** [*十六进制数字*](LexicalStructure.html#hexadecimal_digit) [*十六进制数字*](LexicalStructure.html#hexadecimal_digit) [*十六进制数字*](LexicalStructure.html#hexadecimal_digit) [*十六进制数字*](LexicalStructure.html#hexadecimal_digit) [*十六进制数字*](LexicalStructure.html#hexadecimal_digit) [*十六进制数字*](LexicalStructure.html#hexadecimal_digit) [*十六进制数字*](LexicalStructure.html#hexadecimal_digit) [*十六进制数字*](LexicalStructure.html#hexadecimal_digit)
|
||||
> *转义字符* → **\u {** [*unicode标量数字*](#unicode_scalar_digits) **}**
|
||||
> *unicode标量数字* → 一到八位的十六进制数字
|
||||
|
||||
<a name="operators"></a>
|
||||
<a id="operators"></a>
|
||||
## 运算符
|
||||
|
||||
Swift 标准库定义了许多可供使用的运算符,其中大部分在 [基础运算符](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/BasicOperators.html#//apple_ref/doc/uid/TP40014097-CH6-XID_70) 和 [高级运算符](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/AdvancedOperators.html#//apple_ref/doc/uid/TP40014097-CH27-XID_28) 中进行了阐述。这里将描述哪些字符能用作运算符。
|
||||
Swift 标准库定义了许多可供使用的运算符,其中大部分在 [基础运算符](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/BasicOperators.html#//apple_ref/doc/uid/TP40014097-CH6-XID_70) 和 [高级运算符](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/AdvancedOperators.html#//apple_ref/doc/uid/TP40014097-CH27-XID_28) 中进行了阐述。这一小节将描述哪些字符能用于自定义运算符。
|
||||
|
||||
运算符由一个或多个以下字符组成:
|
||||
`/`、`=`、`-`、`+`、`!`、`*`、`%`、`<`、`>`、`&`、`|`、`^`、`~`、`.`。也就是说,标记 `=`, `->`、`//`、`/*`、`*/`、`.` 以及一元前缀运算符 `&` 属于保留字,这些标记不能被重写或用于自定义运算符。
|
||||
自定义运算符可以由以下其中之一的 ASCII 字符 `/`、`=`、 `-`、`+`、`!`、`*`、`%`、`<`、`>`、`&`、`|`、`^`、`?` 以及 `~`, 或者后面语法中规定的任一个 Unicode 字符开始。在第一个字符之后,允许使用组合型 Unicode 字符。也可以使用两个或者多个的点号来自定义运算符(比如, `....`)。虽然可以自定义包含问号`?`的运算符,但是这个运算符不能只包含单独的一个问号。
|
||||
|
||||
注意:
|
||||
以下这些标记 =, ->, //, /*, */, ., <(前缀运算符), &, and ?, ?(中缀运算符), >(后缀运算符), ! 以及 ? 是被系统保留的。这些标记不能被重载,也不能用于自定义操作符。
|
||||
|
||||
运算符两侧的空白被用来区分该运算符是否为前缀运算符(*prefix operator*)、后缀运算符(*postfix operator*)或二元运算符(*binary operator*)。规则总结如下:
|
||||
|
||||
* 如果运算符两侧都有空白或两侧都无空白,将被看作二元运算符。例如:`a+b` 和 `a + b` 中的运算符 `+` 被看作二元运算符。
|
||||
* 如果运算符只有左侧空白,将被看作前缀一元运算符。例如 `a ++b` 中的 `++` 被看作前缀一元运算符。
|
||||
* 如果运算符只有右侧空白,将被看作后缀一元运算符。例如 `a++ b` 中的 `++` 被看作后缀一元运算符。
|
||||
* 如果运算符左侧没有空白并紧跟 `.`,将被看作后缀一元运算符。例如 `a++.b` 中的 `++` 被看作后缀一元运算符(同理, `a++ . b` 中的 `++` 是后缀一元运算符而 `a ++ .b` 中的 `++` 不是).
|
||||
* 如果运算符左侧没有空白并紧跟 `.`,将被看作后缀一元运算符。例如 `a++.b` 中的 `++` 被看作后缀一元运算符(即上式被视为 `a++ .b` 而非 `a ++ .b`)。
|
||||
|
||||
鉴于这些规则,运算符前的字符 `(`、`[` 和 `{` ;运算符后的字符 `)`、`]` 和 `}` 以及字符 `,`、`;` 和 `:` 都将用于空白检测。
|
||||
鉴于这些规则,运算符前的字符 `(`、`[` 和 `{` ;运算符后的字符 `)`、`]` 和 `}` 以及字符 `,`、`;` 和 `:` 都被视为空白。
|
||||
|
||||
以上规则需注意一点,如果运算符 `!` 或 `?` 左侧没有空白,则不管右侧是否有空白都将被看作后缀运算符。如果将 `?` 用作可选类型(*optional type*)修饰,左侧必须无空白。如果用于条件运算符 `? :`,必须两侧都有空白。
|
||||
以上规则需注意一点,如果预定义运算符 `!` 或 `?` 左侧没有空白,则不管右侧是否有空白都将被看作后缀运算符。如果将 `?` 用作可选链(*optional-chaining*)操作符,左侧必须无空白。如果用于条件运算符 `? :`,必须两侧都有空白。
|
||||
|
||||
在特定构成中 ,以 `<` 或 `>` 开头的运算符会被分离成两个或多个标记,剩余部分以同样的方式会被再次分离。因此,在 `Dictionary<String, Array<Int>>` 中没有必要添加空白来消除闭合字符 `>` 的歧义。在这个例子中, 闭合字符 `>` 被看作单字符标记,而不会被误解为移位运算符 `>>`。
|
||||
在某些特定的构造中 ,以 `<` 或 `>` 开头的运算符会被分离成两个或多个标记,剩余部分以同样的方式会被再次分离。因此,在 `Dictionary<String, Array<Int>>` 中没有必要添加空白来消除闭合字符 `>` 的歧义。在这个例子中, 闭合字符 `>` 不会被视为单独的标记,因而不会被误解析为 `>>` 运算符的一部分。
|
||||
|
||||
要学习如何自定义新的运算符,请参考 [自定义操作符](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/AdvancedOperators.html#//apple_ref/doc/uid/TP40014097-CH27-XID_48) 和 [运算符声明](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Declarations.html#//apple_ref/doc/uid/TP40014097-CH34-XID_644)。学习如何重写现有运算符,请参考 [运算符方法](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/AdvancedOperators.html#//apple_ref/doc/uid/TP40014097-CH27-XID_43)。
|
||||
要学习如何自定义运算符,请参考 [自定义操作符](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/AdvancedOperators.html#//apple_ref/doc/uid/TP40014097-CH27-XID_48) 和 [运算符声明](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Declarations.html#//apple_ref/doc/uid/TP40014097-CH34-XID_644)。要学习如何重载运算符,请参考 [运算符方法](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/AdvancedOperators.html#//apple_ref/doc/uid/TP40014097-CH27-XID_43)。
|
||||
|
||||
> 运算符语法语法
|
||||
> *运算符* → [*运算符字符*](LexicalStructure.html#operator_character) [*运算符*](LexicalStructure.html#operator) _可选_
|
||||
> *运算符字符* → **/** | **=** | **-** | **+** | **!** | ***** | **%** | **<** | **>** | **&** | **|** | **^** | **~** | **.**
|
||||
> *二元运算符* → [*运算符*](LexicalStructure.html#operator)
|
||||
> *前置运算符* → [*运算符*](LexicalStructure.html#operator)
|
||||
> *后置运算符* → [*运算符*](LexicalStructure.html#operator)
|
||||
> *运算符* → [*头部运算符*](#operator_head) [*运算符字符组*](#operator_characters)<sub>可选</sub>
|
||||
> *运算符* → [*头部点运算符*](#dot_operator_head) [*点运算符字符组*](#dot_operator_characters)<sub>可选</sub>
|
||||
<a id="operator_head"></a>
|
||||
> *头部运算符* → **/** | **=** | **+** | **!** |**\*** | **%** |**<** | **>** |**&** | **|** |**/** | **~** | **?** |
|
||||
> *头部运算符* → U+00A1–U+00A7
|
||||
> *头部运算符* → U+00A9 or U+00AB
|
||||
> *头部运算符* → U+00AC or U+00AE
|
||||
> *头部运算符* → U+00B0–U+00B1, U+00B6, U+00BB, U+00BF, U+00D7, or U+00F7
|
||||
> *头部运算符* → U+2016–U+2017 or 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_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_character) [*运算符字符组*] (#operator_characters)<sub>可选</sub>
|
||||
<a id="dot_operator_head"></a>
|
||||
> *头部点运算符* → **..**
|
||||
> *头部点运算符字符* → . | [*运算符字符*](#operator_character)
|
||||
> *头部点运算符字符组* → [*点运算符字符*](#dot_operator_character) [*点运算符字符组*](#dot_operator_characters)<sub>可选</sub>
|
||||
|
||||
> *二元运算符* → [*运算符*](#operator)
|
||||
> *前置运算符* → [*运算符*](#operator)
|
||||
> *后置运算符* → [*运算符*](#operator)
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
> 翻译:[Hawstein](https://github.com/Hawstein)
|
||||
> 校对:[numbbbbb](https://github.com/numbbbbb), [stanzhai](https://github.com/stanzhai)
|
||||
> 校对:[numbbbbb](https://github.com/numbbbbb), [stanzhai](https://github.com/stanzhai), [KYawn](https://github.com/KYawn)
|
||||
|
||||
# 特性
|
||||
-----------------
|
||||
@ -9,7 +9,7 @@
|
||||
- [声明特性](#declaration_attributes)
|
||||
- [类型特性](#type_attributes)
|
||||
|
||||
特性提供了关于声明和类型的更多信息。在Swift中有两类特性,用于修饰声明的以及用于修饰类型的。例如,`required`特性,当应用于一个类的指定或便利初始化器声明时,表明它的每个子类都必须实现那个初始化器。再比如`noreturn`特性,当应用于函数或方法类型时,表明该函数或方法不会返回到它的调用者。
|
||||
特性提供了关于声明和类型的更多信息。在Swift中有两类特性,用于修饰声明的以及用于修饰类型的。
|
||||
|
||||
通过以下方式指定一个特性:符号`@`后面跟特性名,如果包含参数,则把参数带上:
|
||||
|
||||
@ -23,30 +23,44 @@
|
||||
|
||||
声明特性只能应用于声明。然而,你也可以将`noreturn`特性应用于函数或方法类型。
|
||||
|
||||
`availability`
|
||||
`autoclosure`
|
||||
|
||||
这个特性通过把表达式自动封装成无参数的闭包来延迟表达式的计算。它可以声明返回表达式自身类型的没有参数的方法类型,也可以用于函数参数的声明。含有`autoclosure`特性的声明同时也具有`noescape`的特性,除非传递可选参数`escaping`.关于怎样使用`autoclosure`特性的例子,参见[函数类型](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Types.html#//apple_ref/doc/uid/TP40014097-CH31-ID449).
|
||||
|
||||
将`availability`特性用于声明时,将表示该声明的生命周期会依赖于特定的平台和操作系统版本。
|
||||
`availability`特性总会与参数列表一同出现,该参数列表至少有两个参数,参数之间由逗号分隔。第一个参数由以下这些平台名字中的一个起头:iOS, iOSApplicationExtension, OSX, or OSXApplicationExtension。当然,你也可以用一个星号(*)来表示,该声明在上面提到的所有平台上都是有效的。剩下的参数,可以以任何顺序出现,并且可以附加关于声明生命周期的附加信息,包括重要的里程碑。
|
||||
`available`
|
||||
|
||||
- `unavailable`参数表示该声明在特定的平台上是无效的
|
||||
将`available`特性用于声明时,意味着该声明的生命周期会依赖于特定的平台和操作系统版本。
|
||||
|
||||
`available`特性经常与参数列表一同出现,该参数列表至少有两个参数,参数之间由逗号分隔。这些参数由以下这些平台名字中的一个起头:
|
||||
|
||||
- `introduced`参数表示:特定的平台上,该声明被使用的第一个版本。格式如下:<p>`introduced=version number`<p>这里的`version number`由一个正的十进制整数或浮点数构成。
|
||||
- `iOS`
|
||||
- `iOSApplicationExtension`
|
||||
- `OSX`
|
||||
- `OSXApplicationExtension`
|
||||
- `watchOS`
|
||||
|
||||
- `deprecated`参数表示:特定的平台上,该声明被建议弃用的第一个版本。格式如下:
|
||||
当然,你也可以用一个星号(*)来表示,该声明在上面提到的所有平台上都是有效的。
|
||||
|
||||
剩下的参数,可以以任何顺序出现,并且可以添加关于声明生命周期的附加信息,包括重要的里程碑。
|
||||
|
||||
- `unavailable`参数表示:该声明在特定的平台上是无效的
|
||||
|
||||
- `introduced`参数表示:该声明第一次被引入时所在平台的版本。格式如下:
|
||||
<p>`introduced=version number`<p>这里的`version number`由一个正的十进制整数或浮点数构成。
|
||||
|
||||
- `deprecated`参数表示:该声明第一次被建议弃用时所在平台的版本。格式如下:
|
||||
<p>`deprecated=version number`<p>这里的`version number`由一个正的十进制整数或浮点数构成。
|
||||
|
||||
- `obsoleted`参数表示:特定的平台上,该声明被弃用的第一个版本。格式如下:
|
||||
<p>`deprecated=version number`<p>这里的`version number`由一个正的十进制整数或浮点数构成。
|
||||
- `obsoleted`参数表示:该声明第一次被弃用时所在平台的版本。当一个声明被弃用时,它就从此平台中被移除,不能再被使用。格式如下:
|
||||
<p>`obsoleted=version number`<p>这里的`version number`由一个正的十进制整数或浮点数构成。
|
||||
|
||||
- `message`参数用来提供文本信息,并在因使用建议弃用或者被弃用的声明而遇到警告或错误时,由编译器抛出。格式如下:
|
||||
- `message`参数用来提供文本信息。当使用建议弃用或者被弃用的声明时,编译器会抛出错误或警告信息。格式如下:
|
||||
<p>`message=message`<p>这里的`message`由一个字符串文字构成。
|
||||
|
||||
- `renamed`参数用来提供文本信息,用以表示被重命名的声明的新名字。当使用这个重命名的声明遇到错误时,该新名字会被编译器显示出来。格式如下:
|
||||
- `renamed`参数用来提供文本信息,用以表示被重命名的声明的新名字。当使用这个重命名的声明遇到错误时,编译器会显示出该新名字。格式如下:
|
||||
<p>`renamed=new name`<p>这里的`new name`由一个字符串文字构成。
|
||||
|
||||
你可以将`renamed`参数和`unavailable`参数以及类型别名声明组合使用,以向用户表示:在你的代码中,一个声明已经被重命名。当一个声明的名字在一个框架或者库的不同发布版本间发生变化时,这会相当管用。
|
||||
你可以将`renamed`参数和`unavailable`参数以及类型别名声明组合使用,以向用户表示:在你的代码中,一个声明已经被重命名。当一个声明的名字在一个框架或者库的不同发布版本间发生变化时,这会相当有用。
|
||||
|
||||
```swift
|
||||
// First release
|
||||
@ -58,50 +72,34 @@ protocol MyRenamedProtocol {
|
||||
// protocol definition
|
||||
}
|
||||
|
||||
@availability(*, unavailable, renamed="MyRenamedProtocol")
|
||||
@available(*, unavailable, renamed="MyRenamedProtocol")
|
||||
typealias MyProtocol = MyRenamedProtocol
|
||||
```
|
||||
|
||||
|
||||
你可以在一个单独的声明上使用多个`availability`特性,以详细说明该声明在不同平台上的有效性。编译器只有在当前的目标平台和`availability`特性中指定的平台匹配时,才会使用`availability`特性
|
||||
你可以在一个单独的声明上使用多个`available`特性,以详细说明该声明在不同平台上的有效性。编译器只有在当前的目标平台和`available`特性中指定的平台匹配时,才会使用`available`特性
|
||||
|
||||
`autoclosure`
|
||||
如果`available`特性除了平台名称参数外,只指定了一个`introduced `参数,那么可以使用以下简写语法代替:
|
||||
|
||||
这个属性通过把表达式自动封装成不带参数的闭包来延迟表达式的计算。这个属性使用在函数参数声明或者不带参数但是返回表达式类型的方法类型上。含有```autoclosure```属性的声明同时也具有```noescape```的特性,除非传递一个可选的参数属性```escaping```,请看[函数类型](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Types.html#//apple_ref/doc/uid/TP40014097-CH31-ID449)。
|
||||
@available(`platform name` `version number`, *)
|
||||
|
||||
`noescape`
|
||||
|
||||
在函数或者方法声明上使用该属性表示参数将不会被存储用作后续的计算,其用来确保不会超出函数调用的声明周期。使用```noescape```声明属性的函数类型不需要显式的使用```self```,对于其属性或者方法来说。
|
||||
|
||||
`noreturn`
|
||||
|
||||
该特性用于修饰函数或方法声明,表明该函数或方法的对应类型,`T`,是`@noreturn T`。你可以用这个特性修饰函数或方法的类型,这样一来,函数或方法就不会返回到它的调用者中去。
|
||||
|
||||
对于一个没有用`noreturn`特性标记的函数或方法,你可以将它重写(override)为用该特性标记的。相反,对于一个已经用`noreturn`特性标记的函数或方法,你则不可以将它重写为没使用该特性标记的。相同的规则试用于当你在一个comforming类型中实现一个协议方法时。
|
||||
|
||||
`NSApplicationMain`
|
||||
在类上使用该属性表示该类是应用程序委托类,使用该属性与调用```NSApplicationMain```函数并且把该类的名字作为委托类的名字传递给函数的效果相同。
|
||||
|
||||
如果你不想使用这个属性,可以提供一个```main.swift```文件,并且提供一个```main```函数去调用```NSApplicationMain```函数。比如,如果你的应用程序使用一个派生于```NSApplication```的自定义子类作为主要类,你可以调用```NSApplicationMain```函数而不是使用该属性。
|
||||
|
||||
|
||||
`NSCopying`
|
||||
|
||||
该特性用于修饰一个类的存储型变量属性。该特性将使属性的setter与属性值的一个副本合成,由`copyWithZone`方法返回,而不是属性本身的值。该属性的类型必需遵循`NSCopying`协议。
|
||||
|
||||
`NSCopying`特性的行为与Objective-C中的`copy`特性相似。
|
||||
|
||||
`NSManaged`
|
||||
|
||||
该特性用于修饰`NSManagedObject`子类中的存储型变量属性,表明属性的存储和实现由Core Data在运行时基于相关实体描述动态提供。
|
||||
`available`特性的简写语法可以简明地表达出多个平台的可用性。尽管这两种形式在功能上是相同的,但请尽可能地使用简明语法形式。
|
||||
```swift
|
||||
@available(iOS 8.0, OSX 10.10, *)
|
||||
class MyClass {
|
||||
// class definition
|
||||
}
|
||||
```
|
||||
|
||||
`objc`
|
||||
|
||||
该特性用于修饰任意可以在Objective-C中表示的声明,比如,非嵌套类,协议,类和协议中的属性和方法(包含getter和setter),初始化器,析构器,以及下标。`objc`特性告诉编译器该声明可以在Objective-C代码中使用。
|
||||
该特性用于修饰任何可以在Objective-C中表示的声明。比如,非嵌套类、协议、非泛型枚举(仅限整型值类型)、类和协议的属性和方法(包括`getter`和`setter`)、构造器、析构器以及下标。`objc`特性告诉编译器这个声明可以在Objective-C代码中使用。
|
||||
|
||||
如果你将`objc`特性应用于一个类或协议,它也会隐式地应用于那个类或协议的成员。对于标记了`objc`特性的类,编译器会隐式地为它的子类添加`objc`特性。标记了`objc`特性的协议不能继承自没有标记`objc`的协议。
|
||||
如果你将`objc`特性应用于一个类或协议,它也会隐式地应用于那个类的成员或协议。对于标记了`objc`特性的类,编译器会隐式地为它的子类添加`objc`特性。标记了`objc`特性的协议不能继承没有标记`objc`的协议。
|
||||
|
||||
`objc`特性有一个可选的参数,由标记符组成。当你想把`objc`所修饰的实体以一个不同的名字暴露给Objective-C,你就可以使用这个特性参数。你可以使用这个参数来命名类,协议,方法,getters,setters,以及初始化器。下面的例子把`ExampleClass`中`enabled`属性的getter暴露给Objective-C,名字是`isEnabled`,而不是它原来的属性名。
|
||||
如果你将`objc`特性应用于枚举,每一个枚举的`case`都会以枚举名称和`case`名称组合的方式暴露在Objective-C代码中。例如:一个名为`Venus`的`case`在`Planet`枚举中,这个`case`暴露在Objective-C代码中时叫做`PlanetVenus`。
|
||||
|
||||
`objc`特性有一个可选的参数,由标记符组成。当你想把`objc`所修饰的实体以一个不同的名字暴露给Objective-C时,你就可以使用这个特性参数。你可以使用这个参数来命名类,协议,方法,getters,setters,以及构造器。下面的例子把`ExampleClass`中`enabled`属性的getter暴露给Objective-C,名字是`isEnabled`,而不是它原来的属性名。
|
||||
|
||||
```swift
|
||||
@objc
|
||||
@ -114,17 +112,64 @@ class ExampleClass {
|
||||
}
|
||||
```
|
||||
|
||||
`optional`
|
||||
`noescape`
|
||||
|
||||
用该特性修饰协议的属性,方法或下标成员,表示实现这些成员并不需要一致性类型(conforming type)。
|
||||
在函数或者方法声明上使用该特性,它表示参数将不会被存储用作后续的计算,其用来确保不会超出函数调用的生命周期。对于其属性或方法来说,使用`noescape`声明属性的函数类型不需要显式的使用`self.`。
|
||||
|
||||
你只能用`optional`特性修饰那些标记了`objc`特性的协议。因此,只有类类型可以adopt和comform to那些包含可选成员需求的协议。更多关于如何使用`optional`特性以及如何访问可选协议成员的指导,例如,当你不确定一个conforming类型是否实现了它们,请见:[可选协议需求]()。
|
||||
`nonobjc`
|
||||
|
||||
`required`
|
||||
该特性用于方法、属性、下标、或构造器的声明,这些声明本是可以在Objective-C代码中表示的。使用`nonobjc`特性告诉编译器这个声明不能在Objective-C代码中使用。
|
||||
|
||||
用该特性修饰一个类的指定或便利初始化器,表示该类的所有子类都必需实现该初始化器。
|
||||
可以使用`nonobjc`特性解决标有`objc`的类中桥接方法的循环问题,该特性还允许标有`objc`的类的构造器和方法进行重载(overload)。
|
||||
|
||||
加了该特性的指定初始化器必需显式地实现,而便利初始化器既可显式地实现,也可以在子类实现了超类所有指定初始化器后继承而来(或者当子类使用便利初始化器重写了指定初始化器)。
|
||||
标有`nonobjc`特性的方法不能重写(override)一个标有`objc`特性的方法。然而,标有`objc`特性的方法可以重写标有`nonobjc`特性的方法。同样,标有`nonobjc`特性的方法不能满足一个需要标有`@objc`特性的方法的协议。
|
||||
|
||||
`noreturn`
|
||||
|
||||
该特性用于修饰函数或方法声明,表明该函数或方法的对应类型,`T`,是`@noreturn T`。你可以用这个特性修饰函数或方法的类型,这样一来,函数或方法就不会返回到它的调用者中去。
|
||||
|
||||
对于一个没有用`noreturn`特性标记的函数或方法,你可以将它重写为用该特性标记的。相反,对于一个已经用`noreturn`特性标记的函数或方法,你则不可以将它重写为没使用该特性标记的。当你在一个comforming类型中实现一个协议方法时,该规则同样适用。
|
||||
|
||||
`NSApplicationMain`
|
||||
|
||||
在类上使用该特性表示该类是应用程序委托类,使用该特性与调用`NSApplicationMain(_:_:)`函数并且把该类的名字作为委托类的名字传递给函数的效果相同。
|
||||
|
||||
如果你不想使用这个特性,可以提供一个`main.swift`文件,并且提供一个`main`函数去调用`NSApplicationMain(_:_:)`函数。比如,如果你的应用程序使用一个派生于`NSApplication`的自定义子类作为主要类,你可以调用`NSApplicationMain`函数而不是使用该特性。
|
||||
|
||||
`NSCopying`
|
||||
|
||||
该特性用于修饰一个类的存储型变量属性。该特性将使属性的setter与属性值的一个副本合成,这个值由`copyWithZone(_:)`方法返回,而不是属性本身的值。该属性的类型必需遵循`NSCopying`协议。
|
||||
|
||||
`NSCopying`特性的原理与Objective-C中的`copy`特性相似。
|
||||
|
||||
`NSManaged`
|
||||
|
||||
该特性用于修饰`NSManagedObject`子类中的存储型变量属性,表明属性的存储和实现由Core Data在运行时基于相关实体描述动态提供。
|
||||
|
||||
`testable`
|
||||
|
||||
该特性用于`import`声明可以测试的编译模块,它能访问任何标有`internal`权限标识符的实体,这和将它声明为`public`权限标识符有同样的效果。
|
||||
|
||||
`UIApplicationMain`
|
||||
|
||||
在类上使用该特性表示该类是应用程序委托类,使用该特性与调用`UIApplicationMain(_:_:)`函数并且把该类的名字作为委托类的名字传递给函数的效果相同。
|
||||
|
||||
如果你不想使用这个特性,可以提供一个`main.swift`文件,并且提供一个`main`函数去调用`UIApplicationMain(_:_:)`函数。比如,如果你的应用程序使用一个派生于`UIApplication`的自定义子类作为主要类,你可以调用`UIApplicationMain`函数而不是使用该特性。
|
||||
|
||||
`warn_unused_result`
|
||||
|
||||
该特性应用于方法或函数声明,当方法或函数被调用,但其结果未被使用时,该特性会让编译器会产生警告。
|
||||
|
||||
你可以使用这个特性提供一个警告信息,这个警告信息是关于不正确地使用未变异的方法的,这个方法也有一个对应的变异方法。
|
||||
|
||||
`warn_unused_result`有下面两个可选的参数。
|
||||
|
||||
- `message`参数用来提供警告信息,并在因当方法或函数被调用,但其结果未被使用时,显示警告信息。格式如下:
|
||||
<p>`message=message`<p>这里的`message`由一个字符串文字构成。
|
||||
|
||||
- `mutable_variant`参数用于提供变异方法的名称,如果未变异方法以一个可变的值被调用而且其结果并未被使用时,应该使用此变异方法。格式如下(方法名有字符串构成):<p>`mutable_variant=method name`<p>
|
||||
|
||||
比如,Swift标准库提供了变异方法`sortInPlace()`和未变异方法`sort()`集合,它们的元素生成器符合`Comparable`协议。如果你调用了`sort()`方法,而没有使用它的结果,很有可能,你打算使用变异方法`sortInPlace()`替代。
|
||||
|
||||
### Interface Builder使用的声明特性
|
||||
|
||||
@ -137,22 +182,36 @@ Interface Builder特性是Interface Builder用来与Xcode同步的声明特性
|
||||
|
||||
类型特性只能用于修饰类型。然而,你也可以用`noreturn`特性去修饰函数或方法声明。
|
||||
|
||||
`auto_closure`
|
||||
`convention`
|
||||
|
||||
这个特性通过自动地将表达式封闭到一个无参数闭包中来延迟表达式的求值。使用该特性修饰无参的函数或方法类型,返回表达式的类型。一个如何使用`auto_closure`特性的例子,见[函数类型]()
|
||||
该特性用于函数的类型,它指出函数调用的约定。
|
||||
|
||||
`convention`特性有下面几个可选的参数。
|
||||
|
||||
- `swift`参数用于表明一个Swift函数引用。这是Swift中标准的函数值调用约定。
|
||||
|
||||
- `block`参数用于表明一个Objective-C兼容的块引用。函数值表示为一个块对象的引用,这是一个`id-`兼容的Objective-C对象,对象中嵌入了调用函数。调用函数使用C的调用约定。
|
||||
|
||||
- `c`参数用于表明一个C函数引用。函数值没有上下文,这个函数也使用C的调用约定。
|
||||
|
||||
使用C函数调用约定的函数也可用作使用Objective-C块调用约定的函数,同时使用Objective-C块调用约定的函数也可用作使用Swift函数调用约定的函数。然而,只有非泛型的全局函数和本地函数或者不使用任何本地变量的闭包可以被用作使用C函数调用约定的函数。
|
||||
|
||||
`noreturn`
|
||||
|
||||
该特性用于修饰函数或方法的类型,表明该函数或方法不会返回到它的调用者中去。你也可以用它标记函数或方法的声明,表示函数或方法的相应类型,`T`,是`@noreturn T`。
|
||||
|
||||
> 特性语法
|
||||
> *特性* → **@** [*特性名*](..\chapter3\06_Attributes.html#attribute_name) [*特性参数子句*](..\chapter3\06_Attributes.html#attribute_argument_clause) _可选_
|
||||
> *特性名* → [*标识符*](LexicalStructure.html#identifier)
|
||||
> *特性参数子句* → **(** [*平衡令牌列表*](..\chapter3\06_Attributes.html#balanced_tokens) _可选_ **)**
|
||||
> *特性(Attributes)列表* → [*特色*](..\chapter3\06_Attributes.html#attribute) [*特性(Attributes)列表*](..\chapter3\06_Attributes.html#attributes) _可选_
|
||||
> *平衡令牌列表* → [*平衡令牌*](..\chapter3\06_Attributes.html#balanced_token) [*平衡令牌列表*](..\chapter3\06_Attributes.html#balanced_tokens) _可选_
|
||||
> *平衡令牌* → **(** [*平衡令牌列表*](..\chapter3\06_Attributes.html#balanced_tokens) _可选_ **)**
|
||||
> *平衡令牌* → **[** [*平衡令牌列表*](..\chapter3\06_Attributes.html#balanced_tokens) _可选_ **]**
|
||||
> *平衡令牌* → **{** [*平衡令牌列表*](..\chapter3\06_Attributes.html#balanced_tokens) _可选_ **}**
|
||||
> *特性* → **@** [*特性名*](#attribute_name) [*特性参数子句*](#attribute_argument_clause) <sub>_可选_</sub>
|
||||
> *特性名* → [*标识符*](02_Lexical_Structure.html#identifiers)
|
||||
> *特性参数子句* → **(** [*平衡令牌列表*](#balanced_tokens) <sub>_可选_</sub> **)**
|
||||
> *特性(Attributes)列表* → [*特色*](#attribute) [*特性(Attributes)列表*](#attributes) <sub>_可选_</sub>
|
||||
> *平衡令牌列表* → [*平衡令牌*](#balanced_token) [*平衡令牌列表*](#balanced_tokens) <sub>_可选_</sub>
|
||||
> *平衡令牌* → **(** [*平衡令牌列表*](#balanced_tokens) <sub>_可选_</sub> **)**
|
||||
> *平衡令牌* → **[** [*平衡令牌列表*](#balanced_tokens) <sub>_可选_</sub> **]**
|
||||
> *平衡令牌* → **{** [*平衡令牌列表*](#balanced_tokens) <sub>_可选_</sub> **}**
|
||||
> *平衡令牌* → **任意标识符, 关键字, 字面量或运算符**
|
||||
> *平衡令牌* → **任意标点除了(, ), [, ], {, 或 }**
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
> 翻译:[honghaoz](https://github.com/honghaoz)
|
||||
> 翻译:[honghaoz](https://github.com/honghaoz), [ray16897188](https://github.com/ray16897188)
|
||||
> 校对:[numbbbbb](https://github.com/numbbbbb), [stanzhai](https://github.com/stanzhai)
|
||||
|
||||
# 模式(Patterns)
|
||||
@ -11,28 +11,32 @@
|
||||
- [值绑定模式(Value-Binding Pattern)](#value-binding_pattern)
|
||||
- [元组模式(Tuple Pattern)](#tuple_pattern)
|
||||
- [枚举用例模式(Enumeration Case Pattern)](#enumeration_case_pattern)
|
||||
- [类型转换模式(Type-Casting Patterns)](#type-casting_patterns)
|
||||
- [可选模式(Optional Pattern)](#optional_pattern)
|
||||
- [类型转换模式(Type-Casting Pattern)](#type-casting_pattern)
|
||||
- [表达式模式(Expression Pattern)](#expression_pattern)
|
||||
|
||||
模式(pattern)代表了单个值或者复合值的结构。例如,元组`(1, 2)`的结构是逗号分隔的,包含两个元素的列表。因为模式代表一种值的结构,而不是特定的某个值,你可以把模式和各种同类型的值匹配起来。比如,`(x, y)`可以匹配元组`(1, 2)`,以及任何含两个元素的元组。除了将模式与一个值匹配外,你可以从合成值中提取出部分或全部,然后分别把各个部分和一个常量或变量绑定起来。
|
||||
模式(pattern)代表了单个值或者复合值的结构。例如,元组`(1, 2)`的结构是逗号分隔的,包含两个元素的列表。因为模式代表一种值的结构,而不是特定的某个值,你可以把模式和各种同类型的值匹配起来。比如,`(x, y)`可以匹配元组`(1, 2)`,以及任何含两个元素的元组。除了将模式与一个值匹配外,你可以从复合值中提取出部分或全部,然后分别把各个部分和一个常量或变量绑定起来。
|
||||
|
||||
在Swift中,模式出现在变量和常量的声明(在它们的左侧),`for-in`语句和`switch`语句(在它们的case标签)中。尽管任何模式都可以出现在`switch`语句的case标签中,但在其他情况下,只有通配符模式(wildcard pattern),标识符模式(identifier pattern)和包含这两种模式的模式才能出现。
|
||||
swift语言中模式有2个基本的分类:一类能成功和任何值的类型相匹配,另一类在运行时(runtime)和某特定值匹配时可能会失败。
|
||||
|
||||
你可以为通配符模式(wildcard pattern),标识符模式(identifier pattern)和元组模式(tuple pattern)指定类型注释,用来限制这种模式只匹配某种类型的值。
|
||||
第一类模式用于解构简单变量,常量和可选绑定中的值。此类模式包括通配符模式(wildcard patterns),标识符模式(identifier patterns),以及任何包含了它们的值绑定模式(value binding patterns)或者元祖模式(tuple patterns)。你可以为这类模式指定一个类型标注(type annotation)从而限制它们只能匹配某种特定类型的值。
|
||||
|
||||
第二类模式用于全模式匹配,这种情况下你用来相比较的值在运行时可能还不存在。此类模式包括枚举用例模式(enumeration case patterns),可选模式(optional patterns),表达式模式(expression patterns)和类型转换模式(type-casting patterns)。你在`switch`语句的case标签中,`do`语句的`catch`从句中,或者在`if, while, guard`和`for-in`语句的case条件句中使用这类模式。
|
||||
|
||||
> 模式(Patterns) 语法
|
||||
> *模式* → [*通配符模式*](..\chapter3\07_Patterns.html#wildcard_pattern) [*类型注解*](..\chapter3\03_Types.html#type_annotation) _可选_
|
||||
> *模式* → [*标识符模式*](..\chapter3\07_Patterns.html#identifier_pattern) [*类型注解*](..\chapter3\03_Types.html#type_annotati(Value Binding)on) _可选_
|
||||
> *模式* → [*通配符模式*](..\chapter3\07_Patterns.html#wildcard_pattern) [*类型标注*](..\chapter3\03_Types.html#type_annotation) _可选_
|
||||
> *模式* → [*标识符模式*](..\chapter3\07_Patterns.html#identifier_pattern) [*类型标注*](..\chapter3\03_Types.html#type_annotati(Value Binding)on) _可选_
|
||||
> *模式* → [*值绑定模式*](..\chapter3\07_Patterns.html#value_binding_pattern)
|
||||
> *模式* → [*元组模式*](..\chapter3\07_Patterns.html#tuple_pattern) [*类型注解*](..\chapter3\03_Types.html#type_annotation) _可选_
|
||||
> *模式* → [*enum-case-pattern*](..\chapter3\07_Patterns.html#enum_case_pattern)
|
||||
> *模式* → [*type-casting-pattern*](..\chapter3\07_Patterns.html#type_casting_pattern)
|
||||
> *模式* → [*元组模式*](..\chapter3\07_Patterns.html#tuple_pattern) [*类型标注*](..\chapter3\03_Types.html#type_annotation) _可选_
|
||||
> *模式* → [*枚举用例模式*](..\chapter3\07_Patterns.html#enum_case_pattern)
|
||||
> *模式* → [*可选模式*](..\chapter3\07_Patterns.html#optional_pattern)
|
||||
> *模式* → [*类型转换模式*](..\chapter3\07_Patterns.html#type_casting_pattern)
|
||||
> *模式* → [*表达式模式*](..\chapter3\07_Patterns.html#expression_pattern)
|
||||
|
||||
<a name="wildcard_pattern"></a>
|
||||
## 通配符模式(Wildcard Pattern)
|
||||
|
||||
通配符模式匹配并忽略任何值,包含一个下划线(_)。当你不关心被匹配的值时,可以使用此模式。例如,下面这段代码进行了`1...3`的循环,并忽略了每次循环的值:
|
||||
通配符模式由一个下划线(_)构成,且匹配并忽略任何值。当你不在乎被匹配的值时可以使用该模式。例如,下面这段代码在闭区间`1...3`中循环,每次循环时忽略该区间内的当前值:
|
||||
|
||||
```swift
|
||||
for _ in 1...3 {
|
||||
@ -46,7 +50,7 @@ for _ in 1...3 {
|
||||
<a name="identifier_pattern"></a>
|
||||
## 标识符模式(Identifier Pattern)
|
||||
|
||||
标识符模式匹配任何值,并将匹配的值和一个变量或常量绑定起来。例如,在下面的常量申明中,`someValue`是一个标识符模式,匹配了类型是`Int`的`42`。
|
||||
标识符模式匹配任何值,并将匹配的值和一个变量或常量绑定起来。例如,在下面的常量声明中,`someValue`是一个标识符模式,匹配了类型是`Int`的`42`。
|
||||
|
||||
```swift
|
||||
let someValue = 42
|
||||
@ -54,7 +58,7 @@ let someValue = 42
|
||||
|
||||
当匹配成功时,`42`被绑定(赋值)给常量`someValue`。
|
||||
|
||||
当一个变量或常量申明的左边是标识符模式时,此时,标识符模式是隐式的值绑定模式(value-binding pattern)。
|
||||
如果一个变量或常量声明的左边的模式是一个标识符模式,那么这个标识符模式是一个隐式的值绑定模式(value-binding pattern)。
|
||||
|
||||
> 标识符模式语法
|
||||
> *标识符模式* → [*标识符*](LexicalStructure.html#identifier)
|
||||
@ -62,21 +66,21 @@ let someValue = 42
|
||||
<a name="value-binding_pattern"></a>
|
||||
## 值绑定模式(Value-Binding Pattern)
|
||||
|
||||
值绑定模式绑定匹配的值到一个变量或常量。当绑定匹配值给常量时,用关键字`let`,绑定给变量时,用关键字`var`。
|
||||
值绑定模式把匹配到的值绑定给一个变量或常量名。把绑定匹配到的值绑定给常量时,用关键字`let`,绑定给变量时,用关键字`var`。
|
||||
|
||||
标识符模式包含在值绑定模式中,绑定新的变量或常量到匹配的值。例如,你可以分解一个元组的元素,并把每个元素绑定到相应的标识符模式中。
|
||||
在值绑定模式中的标识符模式会把新命名的变量或常量与匹配值做绑定。例如,你可以拆开一个元组的元素,然后把每个元素绑定到其相应一个的标识符模式中。
|
||||
|
||||
```swift
|
||||
let point = (3, 2)
|
||||
switch point {
|
||||
// Bind x and y to the elements of point.
|
||||
case let (x, y):
|
||||
println("The point is at (\(x), \(y)).")
|
||||
print("The point is at (\(x), \(y)).")
|
||||
}
|
||||
// prints "The point is at (3, 2).”
|
||||
```
|
||||
|
||||
在上面这个例子中,`let`将元组模式`(x, y)`分配到各个标识符模式。因为这种行为,`switch`语句中`case let (x, y):`和`case (let x, let y):`匹配的值是一样的。
|
||||
在上面这个例子中,`let`将元组模式`(x, y)`分配到各个标识符模式。正是由于这么做,`switch`语句中`case let (x, y):`和`case (let x, let y):`匹配到的值是一样的。
|
||||
|
||||
> 值绑定(Value Binding)模式语法
|
||||
> *值绑定模式* → **var** [*模式*](..\chapter3\07_Patterns.html#pattern) | **let** [*模式*](..\chapter3\07_Patterns.html#pattern)
|
||||
@ -84,11 +88,11 @@ case let (x, y):
|
||||
<a name="tuple_pattern"></a>
|
||||
## 元组模式(Tuple Pattern)
|
||||
|
||||
元组模式是逗号分隔的列表,包含一个或多个模式,并包含在一对圆括号中。元组模式匹配相应元组类型的值。
|
||||
元组模式是逗号分隔的,有零个或多个模式的列表,并被一对圆括号括起来。元组模式匹配相应元组类型的值。
|
||||
|
||||
你可以使用类型注释来限制一个元组模式来匹配某种元组类型。例如,在常量申明`let (x, y): (Int, Int) = (1, 2)`中的元组模式`(x, y): (Int, Int)`,只匹配两个元素都是`Int`这种类型的元组。如果仅需要限制一个元组模式中的某几个元素,只需要直接对这几个元素提供类型注释即可。例如,在`let (x: String, y)`中的元组模式,只要某个元组类型是包含两个元素,且第一个元素类型是`String`,则被匹配。
|
||||
你可以使用类型标注去限制一个元组模式能匹配哪些种元组类型。例如,在常量声明`let (x, y): (Int, Int) = (1, 2)`中的元组模式`(x, y): (Int, Int)`只匹配两个元素都是`Int`这种类型的元组。如果仅需要限制一个元组模式中的某几个元素,只需要直接对这几个元素提供类型标注即可。例如,在`let (x: String, y)`中的元组模式可以和任何有两个元素,且第一个元素类型是`String`的元组类型匹配。
|
||||
|
||||
当元组模式被用在`for-in`语句或者变量或常量申明时,它可以包含通配符模式,标识符模式或者其他包含这两种模式的模式。例如,下面这段代码是不正确的,因为`(x, 0)`中的元素`0`是一个表达式模式:
|
||||
当元组模式被用在`for-in`语句或者变量或常量声明时,它仅可以包含通配符模式,标识符模式,可选模式或者其他包含这些模式的元祖模式。比如下面这段代码就不正确,因为`(x, 0)`中的元素`0`是一个表达式模式:
|
||||
|
||||
```swift
|
||||
let points = [(0, 0), (1, 0), (1, 1), (2, 0), (2, 1)]
|
||||
@ -98,7 +102,7 @@ for (x, 0) in points {
|
||||
}
|
||||
```
|
||||
|
||||
对于只包含一个元素的元组,括号是不起作用的。模式匹配那个单个元素的类型。例如,下面是等效的:
|
||||
对于只包含一个元素的元组,括号是不起作用的。模式只匹配这个单个元素的类型。举例来说,下面3条语句是等效的:
|
||||
|
||||
```swift
|
||||
let a = 2 // a: Int = 2
|
||||
@ -114,24 +118,59 @@ let (a): Int = 2 // a: Int = 2
|
||||
<a name="enumeration_case_pattern"></a>
|
||||
## 枚举用例模式(Enumeration Case Pattern)
|
||||
|
||||
枚举用例模式匹配现有的枚举类型的某种用例。枚举用例模式仅在`switch`语句中的`case`标签中出现。
|
||||
一个枚举用例模式匹配现有的某个枚举类型的某个用例(case)。枚举用例模式出现在`switch`语句中的case标签中,以及`if`,`while`,`guard`和`for-in`语句的case条件中。
|
||||
|
||||
如果你准备匹配的枚举用例有任何关联的值,则相应的枚举用例模式必须指定一个包含每个关联值元素的元组模式。关于使用`switch`语句来匹配包含关联值枚举用例的例子,请参阅`Associated Values`.
|
||||
|
||||
> 枚举用例模式语法
|
||||
> *enum-case-pattern* → [*类型标识*](..\chapter3\03_Types.html#type_identifier) _可选_ **.** [*枚举的case名*](..\chapter3\05_Declarations.html#enum_case_name) [*元组模式*](..\chapter3\07_Patterns.html#tuple_pattern) _可选_
|
||||
|
||||
<a name="optional_pattern"></a>
|
||||
## 可选模式(Optional Pattern)
|
||||
|
||||
可选模式与封装在一个`Optional(T)`或者一个`ExplicitlyUnwrappedOptional(T)`枚举中的`Some(T)`用例相匹配。可选模式由一个标识符模式和紧随其后的一个问号组成,在某些情况下表现为枚举用例模式。
|
||||
|
||||
由于可选模式是`optional`和`ImplicitlyUnwrappedOptional`枚举用例模式的语法糖(syntactic sugar),下面的2种写法是一样的:
|
||||
|
||||
```swift
|
||||
let someOptional: Int? = 42
|
||||
// Match using an enumeration case pattern
|
||||
if case .Some(let x) = someOptional {
|
||||
print(x)
|
||||
}
|
||||
|
||||
// Match using an optional pattern
|
||||
if case let x? = someOptional {
|
||||
print(x)
|
||||
}
|
||||
```
|
||||
如果一个数组的元素是可选类型,可选模式为`for-in`语句提供了一种在该数组中迭代的简便方式,只为数组中的非空`non-nil`元素执行循环体。
|
||||
|
||||
```swift
|
||||
let arrayOfOptionalInts: [Int?] = [nil, 2, 3, nil, 5]
|
||||
// Match only non-nil values
|
||||
for case let number? in arrayOfOptinalInts {
|
||||
print("Found a \(number)")
|
||||
}
|
||||
//Found a 2
|
||||
//Found a 3
|
||||
//Found a 5
|
||||
|
||||
```
|
||||
> 可选模式语法
|
||||
> *可选模式* → [*标识符模式*](..\chapter3\03_Types.html#type_identifier) ?
|
||||
|
||||
<a name="type-casting_patterns"></a>
|
||||
## 类型转换模式(Type-Casting Patterns)
|
||||
|
||||
有两种类型转换模式,`is`模式和`as`模式。这两种模式均只出现在`switch`语句中的`case`标签中。`is`模式和`as`模式有以下形式:
|
||||
有两种类型转换模式,`is`模式和`as`模式。这两种模式只出现在`switch`语句中的case标签中。`is`模式和`as`模式有以下形式:
|
||||
|
||||
> is `type`
|
||||
> `pattern` as `type`
|
||||
|
||||
`is`模式匹配一个值,如果这个值的类型在运行时(runtime)和`is`模式右边的指定类型(或者那个类型的子类)是一致的。`is`模式和`is`操作符一样,它们都进行类型转换,但是抛弃了返回的类型。
|
||||
`is`模式仅当一个值的类型在运行时(runtime)和`is`模式右边的指定类型一致 - 或者是该类型的子类 - 的情况下,才会匹配这个值。`is`模式和`is`操作符有相似表现,它们都进行类型转换,却舍弃返回的类型。
|
||||
|
||||
`as`模式匹配一个值,如果这个值的类型在运行时(runtime)和`as`模式右边的指定类型(或者那个类型的子类)是一致的。一旦匹配成功,匹配的值的类型被转换成`as`模式左边指定的模式。
|
||||
`as`模式仅当一个值的类型在运行时(runtime)和`as`模式右边的指定类型一致 - 或者是该类型的子类 - 的情况下,才会匹配这个值。如果匹配成功,被匹配的值的类型被转换成`as`模式左边指定的模式。
|
||||
|
||||
关于使用`switch`语句来匹配`is`模式和`as`模式值的例子,请参阅`Type Casting for Any and AnyObject`。
|
||||
|
||||
@ -143,24 +182,24 @@ let (a): Int = 2 // a: Int = 2
|
||||
<a name="expression_pattern"></a>
|
||||
## 表达式模式(Expression Pattern)
|
||||
|
||||
表达式模式代表了一个表达式的值。这个模式只出现在`switch`语句中的`case`标签中。
|
||||
一个表达式模式代表了一个表达式的值。表达式模式只出现在`switch`语句中的`case`标签中。
|
||||
|
||||
由表达式模式所代表的表达式用Swift标准库中的`~=`操作符与输入表达式的值进行比较。如果`~=`操作符返回`true`,则匹配成功。默认情况下,`~=`操作符使用`==`操作符来比较两个相同类型的值。它也可以匹配一个整数值与一个`Range`对象中的整数范围,正如下面这个例子所示:
|
||||
由表达式模式所代表的表达式与使用了Swift标准库中`~=`操作符的输入表达式的值进行比较。如果`~=`操作符返回`true`,则匹配成功。默认情况下,`~=`操作符使用`==`操作符来比较两个相同类型的值。它也可以将一个整型数值与一个`Range`对象中的一段整数区间做匹配,正如下面这个例子所示:
|
||||
|
||||
```swift
|
||||
let point = (1, 2)
|
||||
switch point {
|
||||
case (0, 0):
|
||||
println("(0, 0) is at the origin.")
|
||||
print("(0, 0) is at the origin.")
|
||||
case (-2...2, -2...2):
|
||||
println("(\(point.0), \(point.1)) is near the origin.")
|
||||
print("(\(point.0), \(point.1)) is near the origin.")
|
||||
default:
|
||||
println("The point is at (\(point.0), \(point.1)).")
|
||||
print("The point is at (\(point.0), \(point.1)).")
|
||||
}
|
||||
// prints "(1, 2) is near the origin.”
|
||||
```
|
||||
|
||||
你可以重载`~=`操作符来提供自定义的表达式行为。例如,你可以重写上面的例子,以实现用字符串表达的点来比较`point`表达式。
|
||||
你可以重载`~=`操作符来提供自定义的表达式匹配行为。比如你可以重写上面的例子,拿`point`表达式去比较字符串形式的点。
|
||||
|
||||
```swift
|
||||
// Overload the ~= operator to match a string with an integer
|
||||
@ -169,11 +208,9 @@ func ~=(pattern: String, value: Int) -> Bool {
|
||||
}
|
||||
switch point {
|
||||
case ("0", "0"):
|
||||
println("(0, 0) is at the origin.")
|
||||
case ("-2...2", "-2...2"):
|
||||
println("(\(point.0), \(point.1)) is near the origin.")
|
||||
print("(0, 0) is at the origin.")
|
||||
default:
|
||||
println("The point is at (\(point.0), \(point.1)).")
|
||||
print("The point is at (\(point.0), \(point.1)).")
|
||||
}
|
||||
// prints "(1, 2) is near the origin.”
|
||||
```
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
> 翻译:[fd5788](https://github.com/fd5788)
|
||||
> 校对:[yankuangshi](https://github.com/yankuangshi), [stanzhai](https://github.com/stanzhai)
|
||||
> 校对:[yankuangshi](https://github.com/yankuangshi), [stanzhai](https://github.com/stanzhai), [wardenNScaiyi](https:github.com/wardenNScaiyi)
|
||||
|
||||
# 泛型参数
|
||||
---------
|
||||
@ -9,28 +9,29 @@
|
||||
- [泛型形参子句](#generic_parameter)
|
||||
- [泛型实参子句](#generic_argument)
|
||||
|
||||
本节涉及泛型类型、泛型函数以及泛型构造器的参数,包括形参和实参。声明泛型类型、函数或构造器时,须指定相应的类型参数。类型参数相当于一个占位符,当实例化泛型类型、调用泛型函数或泛型构造器时,就用具体的类型实参替代之。
|
||||
本节涉及泛型类型、泛型函数以及泛型初始化器(**initializer**)的参数,包括形参和实参。声明泛型类型、函数或初始化器时,须指定相应的类型参数。类型参数相当于一个占位符,当实例化泛型类型、调用泛型函数或泛型初始化器时,就用具体的类型实参替代之。
|
||||
|
||||
关于 Swift 语言的泛型概述,见[泛型](../charpter2/22_Generics.md)(第二部分第22章)。
|
||||
|
||||
<a name="generic_parameter"></a>
|
||||
## 泛型形参子句
|
||||
|
||||
泛型形参子句指定泛型类型或函数的类型形参,以及这些参数的关联约束和要求。泛型形参子句用尖括号(<>)包住,并且有以下两种形式:
|
||||
泛型形参子句指定泛型类型或函数的类型形参,以及这些参数的关联约束和关联类型要求(**requirement**)。泛型形参子句用尖括号(<>)包住,并且有以下两种形式:
|
||||
|
||||
> <`generic parameter list`>
|
||||
> <`generic parameter list` where `requirements`>
|
||||
> <`泛型形参列表`>
|
||||
> <`泛型形参列表` where `关联类型要求`>
|
||||
|
||||
泛型形参列表中泛型形参用逗号分开,每一个采用以下形式:
|
||||
泛型形参列表中泛型形参用逗号分开,其中每一个采用以下形式:
|
||||
|
||||
> `type parameter` : `constrain`
|
||||
> `类型形参` : `约束`
|
||||
|
||||
泛型形参由两部分组成:类型形参及其后的可选约束。类型形参只是占位符类型(如T,U,V,KeyType,ValueType等)的名字而已。你可以在泛型类型、函数的其余部分或者构造器声明,以及函数或构造器的签名中使用它。
|
||||
泛型形参由两部分组成:类型形参及其后的可选约束。类型形参只是占位符类型(如 T,U,V,Key,Value 等)的名字而已。你可以在泛型类型、函数的其余部分或者初始化器声明,包括函数或初始化器的签名中使用它(与其任何相关类型)。
|
||||
|
||||
约束用于指明该类型形参继承自某个类或者遵守某个协议或协议的一部分。例如,在下面的泛型函数中,泛型形参`T: Comparable`表示任何用于替代类型形参`T`的类型实参必须满足`Comparable`协议。
|
||||
|
||||
约束用于指明该类型形参继承自某个类或者遵守某个协议或协议的一部分。例如,在下面的泛型中,泛型形参`T: Comparable`表示任何用于替代类型形参`T`的类型实参必须满足`Comparable`协议。
|
||||
|
||||
```swift
|
||||
func simpleMin<T: Comparable>(x: T, y: T) -> T {
|
||||
func simpleMax<T: Comparable>(x: T, _ y: T) -> T {
|
||||
if x < y {
|
||||
return y
|
||||
}
|
||||
@ -38,28 +39,30 @@ func simpleMin<T: Comparable>(x: T, y: T) -> T {
|
||||
}
|
||||
```
|
||||
|
||||
如,`Int`和`Double`均满足`Comparable`协议,该函数接受任何一种类型。与泛型类型相反,调用泛型函数或构造器时不需要指定泛型实参子句。类型实参由传递给函数或构造器的实参推断而出。
|
||||
|
||||
```swift
|
||||
simpleMin(17, 42) // T is inferred to be Int
|
||||
simpleMin(3.14159, 2.71828) // T is inferred to be Double
|
||||
|
||||
如,`Int`和`Double`均满足`Comparable`协议,该函数接受任何一种类型。与泛型类型相反,调用泛型函数或初始化器时不需要指定泛型实参子句。类型实参由传递给函数或初始化器的实参推断而出。
|
||||
|
||||
|
||||
```
|
||||
simpleMax(17, 42) // T被推断出为Int类型
|
||||
simpleMax(3.14159, 2.71828) // T被推断出为Double类型
|
||||
```
|
||||
|
||||
## Where 子句
|
||||
|
||||
要想对类型形参及其关联类型指定额外要求,可以在泛型形参列表之后添加`where`子句。`where`子句由关键字`where`及其后的用逗号分割的多个要求组成。
|
||||
要想对类型形参及其关联类型指定额外关联类型要求,可以在泛型形参列表之后添加`where`子句。`where`子句由关键字`where`及其后的用逗号分割的多个关联类型要求组成。
|
||||
|
||||
`where`子句中的要求用于指明该类型形参继承自某个类或遵守某个协议或协议的一部分。尽管`where`子句有助于表达类型形参上的简单约束(如`T: Comparable`等同于`T where T: Comparable`,等等),但是依然可以用来对类型形参及其关联约束提供更复杂的约束。如,`<T where T: C, T: P>`表示泛型类型`T`继承自类`C`且遵守协议`P`。
|
||||
`where`子句中的关联关系用于指明该类型形参继承自某个类或遵守某个协议或协议的一部分。尽管`where`子句提供了语法糖使其有助于表达类型形参上的简单约束(如`T: Comparable`等同于`T where T: Comparable`,等等),但是依然可以用来对类型形参及其关联类型提供更复杂的约束。如,`<T where T: C, T: P>`表示泛型类型`T`继承自类`C`且遵守协议`P`。
|
||||
|
||||
如上所述,可以强制约束类型形参的关联类型遵守某个协议。`<T: Generator where T.Element: Equatable>`表示`T`遵守`Generator`协议,而且`T`的关联类型`T.Element`遵守`Eauatable`协议(`T`有关联类型是因为`Generator`声明了`Element`,而`T`遵守`Generator`协议)。
|
||||
如上所述,可以强制约束类型形参的关联类型遵守某个协议。例如`<T: Generator where T.Element: Equatable>`表示`T`遵守`Generator`协议,而且`T`的关联类型`T.Element`遵守`Eauatable`协议(`T`有关联类型`Element`是因为`Generator`声明了`Element`,而`T`遵守`Generator`协议)。
|
||||
|
||||
也可以用操作符`==`来指定两个类型等效的要求。例如,有这样一个约束:`T`和`U`遵守`Generator`协议,同时要求它们的关联类型等同,可以这样来表达:`<T: Generator, U: Generator where T.Element == U.Element>`。
|
||||
也可以用操作符`==`来指定两个类型等效的关联关系。例如,有这样一个约束:`T`和`U`遵守`Generator`协议,同时要求它们的关联类型等同,可以这样来表达:`<T: Generator, U: Generator where T.Element == U.Element>`。
|
||||
|
||||
当然,替代类型形参的类型实参必须满足所有类型形参所要求的约束和要求。
|
||||
当然,替代类型形参的类型实参必须满足所有类型形参的约束和关联类型要求。
|
||||
|
||||
泛型函数或构造器可以重载,但在泛型形参子句中的类型形参必须有不同的约束或要求,抑或二者皆不同。当调用重载的泛型函数或构造器时,编译器会用这些约束来决定调用哪个重载函数或构造器。
|
||||
泛型函数或初始化器可以重载,但在泛型形参子句中的类型形参必须有不同的约束或关联类型要求,抑或二者皆不同。当调用重载的泛型函数或始化器时,编译器会用这些约束来决定调用哪个重载函数或始化器。
|
||||
|
||||
泛型类可以生成一个子类,但是这个子类也必须是泛型类。
|
||||
|
||||
> 泛型形参子句语法
|
||||
> *泛型参数子句* → **<** [*泛型参数列表*](GenericParametersAndArguments.html#generic_parameter_list) [*约束子句*](GenericParametersAndArguments.html#requirement_clause) _可选_ **>**
|
||||
@ -80,25 +83,28 @@ simpleMin(3.14159, 2.71828) // T is inferred to be Double
|
||||
|
||||
泛型实参子句指定_泛型类型_的类型实参。泛型实参子句用尖括号(<>)包住,形式如下:
|
||||
|
||||
> <`generic argument list`>
|
||||
> <`泛型实参列表`>
|
||||
|
||||
泛型实参列表中类型实参有逗号分开。类型实参是实际具体类型的名字,用来替代泛型类型的泛型形参子句中的相应的类型形参。从而得到泛型类型的一个特化版本。如,Swift标准库的泛型字典类型定义如下:
|
||||
|
||||
|
||||
```swift
|
||||
struct Dictionary<KeyTypel: Hashable, ValueType>: Collection, DictionaryLiteralConvertible {
|
||||
|
||||
/* .. */
|
||||
|
||||
}
|
||||
```
|
||||
|
||||
泛型`Dictionary`类型的特化版本,`Dictionary<String, Int>`就是用具体的`String`和`Int`类型替代泛型类型`KeyType: Hashable`和`ValueType`产生的。每一个类型实参必须满足它所替代的泛型形参的所有约束,包括任何`where`子句所指定的额外的要求。上面的例子中,类型形参`KeyType`要求满足`Hashable`协议,因此`String`也必须满足`Hashable`协议。
|
||||
泛型`Dictionary`类型的特化版本,`Dictionary<String, Int>`就是用具体的`String`和`Int`类型替代泛型类型`KeyType: Hashable`和`ValueType`产生的。每一个类型实参必须满足它所替代的泛型形参的所有约束,包括任何`where`子句所指定的额外的关联类型要求。上面的例子中,类型形参`Key`类型要求满足`Hashable`协议,因此`String`也必须满足`Hashable`协议。
|
||||
|
||||
可以用本身就是泛型类型的特化版本的类型实参替代类型形参(假设已满足合适的约束和要求)。例如,为了生成一个元素类型是整型数组的数组,可以用数组的特化版本`Array<Int>`替代泛型类型`Array<T>`的类型形参`T`来实现。
|
||||
可以用本身就是泛型类型的特化版本的类型实参替代类型形参(假设已满足合适的约束和关联类型要求)。例如,为了生成一个元素类型是整型数组的数组,可以用数组的特化版本`Array<Int>`替代泛型类型`Array<T>`的类型形参 `T` 来实现。
|
||||
|
||||
```swift
|
||||
```
|
||||
let arrayOfArrays: Array<Array<Int>> = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
|
||||
```
|
||||
|
||||
如[泛型形参子句](#generic_parameter)所述,不能用泛型实参子句来指定泛型函数或构造器的类型实参。
|
||||
如[泛型形参子句](#generic_parameter)所述,不能用泛型实参子句来指定泛型函数或初始化器的类型实参。
|
||||
|
||||
> 泛型实参子句语法
|
||||
> *(泛型参数子句Generic Argument Clause)* → **<** [*泛型参数列表*](GenericParametersAndArguments.html#generic_argument_list) **>**
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
> 翻译:[stanzhai](https://github.com/stanzhai)
|
||||
> 校对:[xielingwang](https://github.com/xielingwang)
|
||||
> 校对:[xielingwang](https://github.com/xielingwang), [miaosiqi](https://github.com/miaosiqi)
|
||||
|
||||
# 语法总结
|
||||
_________________
|
||||
@ -10,7 +10,7 @@ _________________
|
||||
* [泛型参数(Generic Parameters and Arguments)](#generic_parameters_and_arguments)
|
||||
* [声明(Declarations)](#declarations)
|
||||
* [模式(Patterns)](#patterns)
|
||||
* [特性(Attributes)](#attributes)
|
||||
* [属性(Attributes)](#attributes)
|
||||
* [表达式(Expressions)](#expressions)
|
||||
* [词法结构(Lexical Structure)](#lexical_structure)
|
||||
* [类型(Types)](#types)
|
||||
@ -25,6 +25,10 @@ _________________
|
||||
> *语句* → [*分支语句*](..\chapter3\10_Statements.html#branch_statement) **;** _可选_
|
||||
> *语句* → [*标记语句(Labeled Statement)*](..\chapter3\10_Statements.html#labeled_statement)
|
||||
> *语句* → [*控制转移语句*](..\chapter3\10_Statements.html#control_transfer_statement) **;** _可选_
|
||||
> *语句* → [*延迟语句*](TODO) **;** _可选_
|
||||
|
||||
> *语句* → [*执行语句*](TODO) **;** _可选_
|
||||
|
||||
> *多条语句(Statements)* → [*语句*](..\chapter3\10_Statements.html#statement) [*多条语句(Statements)*](..\chapter3\10_Statements.html#statements) _可选_
|
||||
|
||||
<!-- -->
|
||||
@ -33,61 +37,89 @@ _________________
|
||||
> *循环语句* → [*for语句*](..\chapter3\10_Statements.html#for_statement)
|
||||
> *循环语句* → [*for-in语句*](..\chapter3\10_Statements.html#for_in_statement)
|
||||
> *循环语句* → [*while语句*](..\chapter3\10_Statements.html#wheetatype类型ile_statement)
|
||||
> *循环语句* → [*do-while语句*](..\chapter3\10_Statements.html#do_while_statement)
|
||||
> *循环语句* → [*repeat-while语句*](..\chapter3\10_Statements.html#do_while_statement)
|
||||
|
||||
<!-- -->
|
||||
|
||||
> For 循环语法
|
||||
> *for语句* → **for** [*for初始条件*](..\chapter3\10_Statements.html#for_init) _可选_ **;** [*表达式*](..\chapter3\04_Expressions.html#expression) _可选_ **;** [*表达式*](..\chapter3\04_Expressions.html#expression) _可选_ [*代码块*](..\chapter3\05_Declarations.html#code_block)
|
||||
> *for语句* → **for** **(** [*for初始条件*](..\chapter3\10_Statements.html#for_init) _可选_ **;** [*表达式*](..\chapter3\04_Expressions.html#expression) _可选_ **;** [*表达式*](..\chapter3\04_Expressions.html#expression) _可选_ **)** [*代码块*](..\chapter3\05_Declarations.html#code_block)
|
||||
> *for初始条件* → [*变量声明*](..\chapter3\05_Declarations.html#variable_declaration) | [*表达式列表*](..\chapter3\04_Expressions.html#expression_list)
|
||||
> *for初始条件* → [*变量声明*](..\chapter3\05_Declarations.html#variable_declaration) | [*表达式集*](..\chapter3\04_Expressions.html#expression_list)
|
||||
|
||||
<!-- -->
|
||||
|
||||
> For-In 循环语法
|
||||
> *for-in语句* → **for** [*模式*](..\chapter3\07_Patterns.html#pattern) **in** [*表达式*](..\chapter3\04_Expressions.html#expression) [*代码块*](..\chapter3\05_Declarations.html#code_block)
|
||||
> *for-in语句* → **for case** _可选_ [*模式*](..\chapter3\07_Patterns.html#pattern) **in** [*表达式*](..\chapter3\04_Expressions.html#expression) [*代码块*](..\chapter3\05_Declarations.html#code_block) [*where从句*](TODO) _可选_
|
||||
|
||||
<!-- -->
|
||||
|
||||
> While 循环语法
|
||||
> *while语句* → **while** [*while条件*](..\chapter3\10_Statements.html#while_condition) [*代码块*](..\chapter3\05_Declarations.html#code_block)
|
||||
> *while条件* → [*表达式*](..\chapter3\04_Expressions.html#expression) | [*声明*](..\chapter3\05_Declarations.html#declaration)
|
||||
> *while语句* → **while** [*条件从句*](..\chapter3\10_Statements.html#while_condition) [*代码块*](..\chapter3\05_Declarations.html#code_block)
|
||||
> *条件从句* → [*表达式*](TODO)
|
||||
|
||||
> *条件从句* → [*表达式*](TODO) *,* [*表达式集*]()
|
||||
|
||||
>*条件从句* → [*表达式集*](TODO)
|
||||
|
||||
> *条件从句* → [*可用条件 (availability-condition*)](TODO) *|* [*表达式集*]()
|
||||
|
||||
> *条件集* → [*条件*](TODO) *|* [*条件*](TODO) *,* [*条件集*]()
|
||||
|
||||
> *条件* → [*可用条件(availability-condition)*](TODO) *|* [*个例条件(case-condition)*](TODO) *|* [*可选绑定条件(optional-binding-condition)*](TODO)
|
||||
|
||||
> *个例条件(case-condition)* → **case** [*模式*](TODO) [*构造器*](TODO) [*where从句*](TODO)_可选_
|
||||
|
||||
> *可选绑定条件(optional-binding-condition)* → [*可选绑定头(optional-binding-head)*](TODO) [*可选绑定连续集(optional-binding-continuation-list)*](TODO) _可选_ [*where从句*](TODO) _可选_
|
||||
|
||||
> *可选绑定头(optional-binding-head)* → **let** [*模式 构造器*](TODO) *|* **var** [*模式 构造器*](TODO)
|
||||
|
||||
> *可选绑定连续集(optional-binding-contiuation-list)* → [*可选绑定连续(optional-binding-contiuation)*](TODO) *|* [*可选绑定连续(optional-binding-contiuation)*](TODO) *,* [*可选绑定连续集(optional-binding-contiuation-list)*](TODO)
|
||||
|
||||
> *可选绑定连续(optional-binding-continuation)* → [*模式 构造器*](TODO) *|* [*可选绑定头(optional-binding-head)*](TODO)
|
||||
|
||||
<!-- -->
|
||||
|
||||
> Do-While 循环语法
|
||||
> *do-while语句* → **do** [*代码块*](..\chapter3\05_Declarations.html#code_block) **while** [*while条件*](..\chapter3\10_Statements.html#while_condition)
|
||||
> Repeat-While语句语法
|
||||
*repeat-while-statement* → **repeat** [*代码块*](TODO) **while** [*表达式*](TODO)
|
||||
|
||||
<!-- -->
|
||||
|
||||
> 分支语句语法
|
||||
> *分支语句* → [*if语句*](..\chapter3\10_Statements.html#if_statement)
|
||||
|
||||
> *分支语句* → [*guard语句*](TODO)
|
||||
|
||||
> *分支语句* → [*switch语句*](..\chapter3\10_Statements.html#switch_statement)
|
||||
|
||||
<!-- -->
|
||||
|
||||
> If语句语法
|
||||
> *if语句* → **if** [*if条件*](..\chapter3\10_Statements.html#if_condition) [*代码块*](..\chapter3\05_Declarations.html#code_block) [*else子句(Clause)*](..\chapter3\10_Statements.html#else_clause) _可选_
|
||||
> *if条件* → [*表达式*](..\chapter3\04_Expressions.html#expression) | [*声明*](..\chapter3\05_Declarations.html#declaration)
|
||||
> *else子句(Clause)* → **else** [*代码块*](..\chapter3\05_Declarations.html#code_block) | **else** [*if语句*](..\chapter3\10_Statements.html#if_statement)
|
||||
> *if语句* → **if** [*条件从句*](TODO) [*代码块*](TODO) [*else从句(Clause)*](TODO) _可选_
|
||||
|
||||
> *else从句(Clause)* → **else** [*代码块*](..\chapter3\05_Declarations.html#code_block) | **else** [*if语句*](..\chapter3\10_Statements.html#if_statement)
|
||||
|
||||
|
||||
<!-- -->
|
||||
>Guard 语句语法
|
||||
>*guard语句* → **guard** [*条件从句*](TODO) **else** [*代码块*](TODO)
|
||||
|
||||
|
||||
<!-- -->
|
||||
|
||||
> Switch语句语法
|
||||
> *switch语句* → **switch** [*表达式*](..\chapter3\04_Expressions.html#expression) **{** [*SwitchCase列表*](..\chapter3\10_Statements.html#switch_cases) _可选_ **}**
|
||||
> *SwitchCase列表* → [*SwitchCase*](..\chapter3\10_Statements.html#switch_case) [*SwitchCase列表*](..\chapter3\10_Statements.html#switch_cases) _可选_
|
||||
> *switch语句* → **switch** [*表达式*](..\chapter3\04_Expressions.html#expression) **{** [*SwitchCase*](..\chapter3\10_Statements.html#switch_cases) _可选_ **}**
|
||||
> *SwitchCase集* → [*SwitchCase*](..\chapter3\10_Statements.html#switch_case) [*SwitchCase集*](..\chapter3\10_Statements.html#switch_cases) _可选_
|
||||
> *SwitchCase* → [*case标签*](..\chapter3\10_Statements.html#case_label) [*多条语句(Statements)*](..\chapter3\10_Statements.html#statements) | [*default标签*](..\chapter3\10_Statements.html#default_label) [*多条语句(Statements)*](..\chapter3\10_Statements.html#statements)
|
||||
> *SwitchCase* → [*case标签*](..\chapter3\10_Statements.html#case_label) **;** | [*default标签*](..\chapter3\10_Statements.html#default_label) **;**
|
||||
> *case标签* → **case** [*case项列表*](..\chapter3\10_Statements.html#case_item_list) **:**
|
||||
> *case项列表* → [*模式*](..\chapter3\07_Patterns.html#pattern) [*guard-clause*](..\chapter3\10_Statements.html#guard_clause) _可选_ | [*模式*](..\chapter3\07_Patterns.html#pattern) [*guard-clause*](..\chapter3\10_Statements.html#guard_clause) _可选_ **,** [*case项列表*](..\chapter3\10_Statements.html#case_item_list)
|
||||
> *case标签* → **case** [*case项集*](..\chapter3\10_Statements.html#case_item_list) **:**
|
||||
> *case项集* → [*模式*](..\chapter3\07_Patterns.html#pattern) [*where-clause*](..\chapter3\10_Statements.html#guard_clause) _可选_ | [*模式*](..\chapter3\07_Patterns.html#pattern) [*where-clause*](..\chapter3\10_Statements.html#guard_clause) _可选_ **,** [*case项集*](..\chapter3\10_Statements.html#case_item_list)
|
||||
> *default标签* → **default** **:**
|
||||
> *guard-clause* → **where** [*guard-expression*](..\chapter3\10_Statements.html#guard_expression)
|
||||
> *guard-expression* → [*表达式*](..\chapter3\04_Expressions.html#expression)
|
||||
> *where从句* → **where** [*where表达式*](TODO)
|
||||
> *where表达式* → [*表达式*](TODO)
|
||||
|
||||
<!-- -->
|
||||
|
||||
> 标记语句语法
|
||||
> *标记语句(Labeled Statement)* → [*语句标签*](..\chapter3\10_Statements.html#statement_label) [*循环语句*](..\chapter3\10_Statements.html#loop_statement) | [*语句标签*](..\chapter3\10_Statements.html#statement_label) [*switch语句*](..\chapter3\10_Statements.html#switch_statement)
|
||||
> *标记语句(Labeled Statement)* → [*语句标签*](..\chapter3\10_Statements.html#statement_label) [*循环语句*](..\chapter3\10_Statements.html#loop_statement) | [*语句标签*](..\chapter3\10_Statements.html#statement_label) [*if语句*](..\chapter3\10_Statements.html#switch_statement) | [*语句标签*](TODY) [*switch语句*](TODY)
|
||||
> *语句标签* → [*标签名称*](..\chapter3\10_Statements.html#label_name) **:**
|
||||
> *标签名称* → [*标识符*](..\chapter3\02_Lexical_Structure.html#identifier)
|
||||
|
||||
@ -98,6 +130,7 @@ _________________
|
||||
> *控制传递语句* → [*continue语句*](..\chapter3\10_Statements.html#continue_statement)
|
||||
> *控制传递语句* → [*fallthrough语句*](..\chapter3\10_Statements.html#fallthrough_statement)
|
||||
> *控制传递语句* → [*return语句*](..\chapter3\10_Statements.html#return_statement)
|
||||
> *控制传递语句* → [*throw语句*](TODO)
|
||||
|
||||
<!-- -->
|
||||
|
||||
@ -119,27 +152,71 @@ _________________
|
||||
> Return 语句语法
|
||||
> *return语句* → **return** [*表达式*](..\chapter3\04_Expressions.html#expression) _可选_
|
||||
|
||||
<!-- -->
|
||||
>可用条件(Availability Condition)语法
|
||||
|
||||
>*可用条件(availability-condition)* → **#available** **(** [*多可用参数*(availability-arguments)](TODO) **)**
|
||||
|
||||
>*多可用参数(availability- arguments)* → [*可用参数(availability-argument)*](TODO)|[*可用参数(availability-argument)*](TODO) , [多可用参数(availability-arguments)](TODO)
|
||||
|
||||
>*可用参数(availability- argument)* → [*平台名(platform-name)*](TODO) [*平台版本(platform-version)*](TODO)
|
||||
|
||||
>*可用参数(availability- argument)* → *
|
||||
|
||||
>*平台名* → **iOS** | **iOSApplicationExtension**
|
||||
|
||||
>*平台名* → **OSX** | **OSXApplicationExtension**
|
||||
|
||||
>*平台名* → **watchOS**
|
||||
|
||||
>*平台版本* → [*十进制数(decimal-digits)*](TODO)
|
||||
|
||||
>*平台版本* → [*十进制数(decimal-digits)*](TODO) . [*十进制数(decimal-digits)*](TODO)
|
||||
|
||||
>*平台版本* → [*十进制数(decimal-digits)*](TODO) **.** [*十进制数(decimal-digits)*](TODO) **.** [*十进制数(decimal-digits)*](TODO))
|
||||
|
||||
<!-- -->
|
||||
>抛出语句(Throw Statement)语法
|
||||
|
||||
>*抛出语句(throw-statement)* → **throw** [*表达式(expression)*](TODO)
|
||||
|
||||
<!-- -->
|
||||
>延迟语句 (defer-statement)语法
|
||||
|
||||
>*延迟语句(defer-statement)* → **defer** [*代码块*](TODO)
|
||||
|
||||
<!-- -->
|
||||
>执行语句(do-statement)语法
|
||||
|
||||
>*执行语句(do-statement)* → **do** [*代码块*](TODO) [*catch-clauses*](TODO) _可选_
|
||||
|
||||
>*catch-clauses* → [*catch-clause*](TODO) [*catch-clauses*](TODO) _可选_
|
||||
|
||||
>*catch-clauses* → **catch** [*模式(pattern)*](TODO) _可选_ [*where-clause*](TODO) _可选_ [*代码块(code-block)*](TODO) _可选_
|
||||
|
||||
|
||||
|
||||
<a name="generic_parameters_and_arguments"></a>
|
||||
## 泛型参数
|
||||
|
||||
> 泛型形参子句(Generic Parameter Clause) 语法
|
||||
> *泛型参数子句* → **<** [*泛型参数列表*](GenericParametersAndArguments.html#generic_parameter_list) [*约束子句*](GenericParametersAndArguments.html#requirement_clause) _可选_ **>**
|
||||
> *泛型参数列表* → [*泛形参数*](GenericParametersAndArguments.html#generic_parameter) | [*泛形参数*](GenericParametersAndArguments.html#generic_parameter) **,** [*泛型参数列表*](GenericParametersAndArguments.html#generic_parameter_list)
|
||||
> 泛型形参从句(Generic Parameter Clause) 语法
|
||||
> *泛型参数从句* → **<** [*泛型参数集*](GenericParametersAndArguments.html#generic_parameter_list) [*约束从句*](GenericParametersAndArguments.html#requirement_clause) _可选_ **>**
|
||||
> *泛型参数集* → [*泛形参数*](GenericParametersAndArguments.html#generic_parameter) | [*泛形参数*](GenericParametersAndArguments.html#generic_parameter) **,** [*泛型参数集*](GenericParametersAndArguments.html#generic_parameter_list)
|
||||
> *泛形参数* → [*类型名称*](..\chapter3\03_Types.html#type_name)
|
||||
> *泛形参数* → [*类型名称*](..\chapter3\03_Types.html#type_name) **:** [*类型标识*](..\chapter3\03_Types.html#type_identifier)
|
||||
> *泛形参数* → [*类型名称*](..\chapter3\03_Types.html#type_name) **:** [*协议合成类型*](..\chapter3\03_Types.html#protocol_composition_type)
|
||||
> *约束子句* → **where** [*约束列表*](GenericParametersAndArguments.html#requirement_list)
|
||||
> *约束列表* → [*约束*](GenericParametersAndArguments.html#requirement) | [*约束*](GenericParametersAndArguments.html#requirement) **,** [*约束列表*](GenericParametersAndArguments.html#requirement_list)
|
||||
> *约束从句* → **where** [*约束集*](GenericParametersAndArguments.html#requirement_list)
|
||||
> *约束集* → [*约束*](GenericParametersAndArguments.html#requirement) | [*约束*](GenericParametersAndArguments.html#requirement) **,** [*约束集*](GenericParametersAndArguments.html#requirement_list)
|
||||
> *约束* → [*一致性约束*](GenericParametersAndArguments.html#conformance_requirement) | [*同类型约束*](GenericParametersAndArguments.html#same_type_requirement)
|
||||
> *一致性约束* → [*类型标识*](..\chapter3\03_Types.html#type_identifier) **:** [*类型标识*](..\chapter3\03_Types.html#type_identifier)
|
||||
> *一致性约束* → [*类型标识*](..\chapter3\03_Types.html#type_identifier) **:** [*协议合成类型*](..\chapter3\03_Types.html#protocol_composition_type)
|
||||
> *同类型约束* → [*类型标识*](..\chapter3\03_Types.html#type_identifier) **==** [*类型标识*](..\chapter3\03_Types.html#type_identifier)
|
||||
> *同类型约束* → [*类型标识*](..\chapter3\03_Types.html#type_identifier) **==** [*类型*](..\chapter3\03_Types.html#type_identifier)
|
||||
|
||||
<!-- -->
|
||||
|
||||
> 泛型实参子句语法
|
||||
> *(泛型参数子句Generic Argument Clause)* → **<** [*泛型参数列表*](GenericParametersAndArguments.html#generic_argument_list) **>**
|
||||
> *泛型参数列表* → [*泛型参数*](GenericParametersAndArguments.html#generic_argument) | [*泛型参数*](GenericParametersAndArguments.html#generic_argument) **,** [*泛型参数列表*](GenericParametersAndArguments.html#generic_argument_list)
|
||||
> 泛型实参从句语法
|
||||
> *(泛型参数从句Generic Argument Clause)* → **<** [*泛型参数集*](GenericParametersAndArguments.html#generic_argument_list) **>**
|
||||
> *泛型参数集* → [*泛型参数*](GenericParametersAndArguments.html#generic_argument) | [*泛型参数*](GenericParametersAndArguments.html#generic_argument) **,** [*泛型参数集*](GenericParametersAndArguments.html#generic_argument_list)
|
||||
> *泛型参数* → [*类型*](..\chapter3\03_Types.html#type)
|
||||
|
||||
<a name="declarations"></a>
|
||||
@ -160,9 +237,8 @@ _________________
|
||||
> *声明* → [*扩展声明*](..\chapter3\05_Declarations.html#extension_declaration)
|
||||
> *声明* → [*下标脚本声明*](..\chapter3\05_Declarations.html#subscript_declaration)
|
||||
> *声明* → [*运算符声明*](..\chapter3\05_Declarations.html#operator_declaration)
|
||||
> *声明(Declarations)列表* → [*声明*](..\chapter3\05_Declarations.html#declaration) [*声明(Declarations)列表*](..\chapter3\05_Declarations.html#declarations) _可选_
|
||||
> *声明描述符(Specifiers)列表* → [*声明描述符(Specifier)*](..\chapter3\05_Declarations.html#declaration_specifier) [*声明描述符(Specifiers)列表*](..\chapter3\05_Declarations.html#declaration_specifiers) _可选_
|
||||
> *声明描述符(Specifier)* → **class** | **mutating** | **nonmutating** | **override** | **static** | **unowned** | **unowned(safe)** | **unowned(unsafe)** | **weak**
|
||||
> *声明(Declarations)集* → [*声明*](..\chapter3\05_Declarations.html#declaration) [*声明(Declarations)集*](..\chapter3\05_Declarations.html#declarations) _可选_
|
||||
|
||||
|
||||
<!-- -->
|
||||
|
||||
@ -177,7 +253,7 @@ _________________
|
||||
<!-- -->
|
||||
|
||||
> 导入(Import)声明语法
|
||||
> *导入声明* → [*特性(Attributes)列表*](..\chapter3\06_Attributes.html#attributes) _可选_ **import** [*导入类型*](..\chapter3\05_Declarations.html#import_kind) _可选_ [*导入路径*](..\chapter3\05_Declarations.html#import_path)
|
||||
> *导入声明* → [*属性(Attributes)集*](..\chapter3\06_Attributes.html#attributes) _可选_ **import** [*导入类型*](..\chapter3\05_Declarations.html#import_kind) _可选_ [*导入路径*](..\chapter3\05_Declarations.html#import_path)
|
||||
> *导入类型* → **typealias** | **struct** | **class** | **enum** | **protocol** | **var** | **func**
|
||||
> *导入路径* → [*导入路径标识符*](..\chapter3\05_Declarations.html#import_path_identifier) | [*导入路径标识符*](..\chapter3\05_Declarations.html#import_path_identifier) **.** [*导入路径*](..\chapter3\05_Declarations.html#import_path)
|
||||
> *导入路径标识符* → [*标识符*](..\chapter3\02_Lexical_Structure.html#identifier) | [*运算符*](..\chapter3\02_Lexical_Structure.html#operator)
|
||||
@ -185,108 +261,117 @@ _________________
|
||||
<!-- -->
|
||||
|
||||
> 常数声明语法
|
||||
> *常量声明* → [*特性(Attributes)列表*](..\chapter3\06_Attributes.html#attributes) _可选_ [*声明描述符(Specifiers)列表*](..\chapter3\05_Declarations.html#declaration_specifiers) _可选_ **let** [*模式构造器列表*](..\chapter3\05_Declarations.html#pattern_initializer_list)
|
||||
> *模式构造器列表* → [*模式构造器*](..\chapter3\05_Declarations.html#pattern_initializer) | [*模式构造器*](..\chapter3\05_Declarations.html#pattern_initializer) **,** [*模式构造器列表*](..\chapter3\05_Declarations.html#pattern_initializer_list)
|
||||
> *常量声明* → [*属性(Attributes)集*](..\chapter3\06_Attributes.html#attributes) _可选_ [*声明修改符(Modifiers)集*](..\chapter3\05_Declarations.html#declaration_specifiers) _可选_ **let** [*模式构造器集*](..\chapter3\05_Declarations.html#pattern_initializer_list)
|
||||
> *模式构造器集* → [*模式构造器*](..\chapter3\05_Declarations.html#pattern_initializer) | [*模式构造器*](..\chapter3\05_Declarations.html#pattern_initializer) **,** [*模式构造器集*](..\chapter3\05_Declarations.html#pattern_initializer_list)
|
||||
> *模式构造器* → [*模式*](..\chapter3\07_Patterns.html#pattern) [*构造器*](..\chapter3\05_Declarations.html#initializer) _可选_
|
||||
> *构造器* → **=** [*表达式*](..\chapter3\04_Expressions.html#expression)
|
||||
|
||||
<!-- -->
|
||||
|
||||
> 变量声明语法
|
||||
> *变量声明* → [*变量声明头(Head)*](..\chapter3\05_Declarations.html#variable_declaration_head) [*模式构造器列表*](..\chapter3\05_Declarations.html#pattern_initializer_list)
|
||||
> *变量声明* → [*变量声明头(Head)*](..\chapter3\05_Declarations.html#variable_declaration_head) [*模式构造器集*](..\chapter3\05_Declarations.html#pattern_initializer_list)
|
||||
> *变量声明* → [*变量声明头(Head)*](..\chapter3\05_Declarations.html#variable_declaration_head) [*变量名*](..\chapter3\05_Declarations.html#variable_name) [*类型注解*](..\chapter3\03_Types.html#type_annotation) [*代码块*](..\chapter3\05_Declarations.html#code_block)
|
||||
> *变量声明* → [*变量声明头(Head)*](..\chapter3\05_Declarations.html#variable_declaration_head) [*变量名*](..\chapter3\05_Declarations.html#variable_name) [*类型注解*](..\chapter3\03_Types.html#type_annotation) [*getter-setter块*](..\chapter3\05_Declarations.html#getter_setter_block)
|
||||
> *变量声明* → [*变量声明头(Head)*](..\chapter3\05_Declarations.html#variable_declaration_head) [*变量名*](..\chapter3\05_Declarations.html#variable_name) [*类型注解*](..\chapter3\03_Types.html#type_annotation) [*getter-setter关键字(Keyword)块*](..\chapter3\05_Declarations.html#getter_setter_keyword_block)
|
||||
> *变量声明* → [*变量声明头(Head)*](..\chapter3\05_Declarations.html#variable_declaration_head) [*变量名*](..\chapter3\05_Declarations.html#variable_name) [*类型注解*](..\chapter3\03_Types.html#type_annotation) [*构造器*](..\chapter3\05_Declarations.html#initializer) _可选_ [*willSet-didSet代码块*](..\chapter3\05_Declarations.html#willSet_didSet_block)
|
||||
> *变量声明头(Head)* → [*特性(Attributes)列表*](..\chapter3\06_Attributes.html#attributes) _可选_ [*声明描述符(Specifiers)列表*](..\chapter3\05_Declarations.html#declaration_specifiers) _可选_ **var**
|
||||
> *变量声明头(Head)* → [*属性(Attributes)集*](..\chapter3\06_Attributes.html#attributes) _可选_ [*声明修改符(Modifers)集*](..\chapter3\05_Declarations.html#declaration_specifiers) _可选_ **var**
|
||||
> *变量名称* → [*标识符*](..\chapter3\02_Lexical_Structure.html#identifier)
|
||||
> *getter-setter块* → **{** [*getter子句*](..\chapter3\05_Declarations.html#getter_clause) [*setter子句*](..\chapter3\05_Declarations.html#setter_clause) _可选_ **}**
|
||||
> *getter-setter块* → **{** [*setter子句*](..\chapter3\05_Declarations.html#setter_clause) [*getter子句*](..\chapter3\05_Declarations.html#getter_clause) **}**
|
||||
> *getter子句* → [*特性(Attributes)列表*](..\chapter3\06_Attributes.html#attributes) _可选_ **get** [*代码块*](..\chapter3\05_Declarations.html#code_block)
|
||||
> *setter子句* → [*特性(Attributes)列表*](..\chapter3\06_Attributes.html#attributes) _可选_ **set** [*setter名称*](..\chapter3\05_Declarations.html#setter_name) _可选_ [*代码块*](..\chapter3\05_Declarations.html#code_block)
|
||||
> *getter-setter块* → **{** [*getter从句*](..\chapter3\05_Declarations.html#getter_clause) [*setter从句*](..\chapter3\05_Declarations.html#setter_clause) _可选_ **}**
|
||||
> *getter-setter块* → **{** [*setter从句*](..\chapter3\05_Declarations.html#setter_clause) [*getter从句*](..\chapter3\05_Declarations.html#getter_clause) **}**
|
||||
> *getter从句* → [*属性(Attributes)集*](..\chapter3\06_Attributes.html#attributes) _可选_ **get** [*代码块*](..\chapter3\05_Declarations.html#code_block)
|
||||
> *setter从句* → [*属性(Attributes)集*](..\chapter3\06_Attributes.html#attributes) _可选_ **set** [*setter名称*](..\chapter3\05_Declarations.html#setter_name) _可选_ [*代码块*](..\chapter3\05_Declarations.html#code_block)
|
||||
> *setter名称* → **(** [*标识符*](..\chapter3\02_Lexical_Structure.html#identifier) **)**
|
||||
> *getter-setter关键字(Keyword)块* → **{** [*getter关键字(Keyword)子句*](..\chapter3\05_Declarations.html#getter_keyword_clause) [*setter关键字(Keyword)子句*](..\chapter3\05_Declarations.html#setter_keyword_clause) _可选_ **}**
|
||||
> *getter-setter关键字(Keyword)块* → **{** [*setter关键字(Keyword)子句*](..\chapter3\05_Declarations.html#setter_keyword_clause) [*getter关键字(Keyword)子句*](..\chapter3\05_Declarations.html#getter_keyword_clause) **}**
|
||||
> *getter关键字(Keyword)子句* → [*特性(Attributes)列表*](..\chapter3\06_Attributes.html#attributes) _可选_ **get**
|
||||
> *setter关键字(Keyword)子句* → [*特性(Attributes)列表*](..\chapter3\06_Attributes.html#attributes) _可选_ **set**
|
||||
> *willSet-didSet代码块* → **{** [*willSet子句*](..\chapter3\05_Declarations.html#willSet_clause) [*didSet子句*](..\chapter3\05_Declarations.html#didSet_clause) _可选_ **}**
|
||||
> *willSet-didSet代码块* → **{** [*didSet子句*](..\chapter3\05_Declarations.html#didSet_clause) [*willSet子句*](..\chapter3\05_Declarations.html#willSet_clause) **}**
|
||||
> *willSet子句* → [*特性(Attributes)列表*](..\chapter3\06_Attributes.html#attributes) _可选_ **willSet** [*setter名称*](..\chapter3\05_Declarations.html#setter_name) _可选_ [*代码块*](..\chapter3\05_Declarations.html#code_block)
|
||||
> *didSet子句* → [*特性(Attributes)列表*](..\chapter3\06_Attributes.html#attributes) _可选_ **didSet** [*setter名称*](..\chapter3\05_Declarations.html#setter_name) _可选_ [*代码块*](..\chapter3\05_Declarations.html#code_block)
|
||||
> *getter-setter关键字(Keyword)块* → **{** [*getter关键字(Keyword)从句*](..\chapter3\05_Declarations.html#getter_keyword_clause) [*setter关键字(Keyword)从句*](..\chapter3\05_Declarations.html#setter_keyword_clause) _可选_ **}**
|
||||
> *getter-setter关键字(Keyword)块* → **{** [*setter关键字(Keyword)从句*](..\chapter3\05_Declarations.html#setter_keyword_clause) [*getter关键字(Keyword)从句*](..\chapter3\05_Declarations.html#getter_keyword_clause) **}**
|
||||
> *getter关键字(Keyword)从句* → [*属性(Attributes)集*](..\chapter3\06_Attributes.html#attributes) _可选_ **get**
|
||||
> *setter关键字(Keyword)从句* → [*属性(Attributes)集*](..\chapter3\06_Attributes.html#attributes) _可选_ **set**
|
||||
> *willSet-didSet代码块* → **{** [*willSet从句*](..\chapter3\05_Declarations.html#willSet_clause) [*didSet从句*](..\chapter3\05_Declarations.html#didSet_clause) _可选_ **}**
|
||||
> *willSet-didSet代码块* → **{** [*didSet从句*](..\chapter3\05_Declarations.html#didSet_clause) [*willSet从句*](..\chapter3\05_Declarations.html#willSet_clause) **}**
|
||||
> *willSet从句* → [*属性(Attributes)集*](..\chapter3\06_Attributes.html#attributes) _可选_ **willSet** [*setter名称*](..\chapter3\05_Declarations.html#setter_name) _可选_ [*代码块*](..\chapter3\05_Declarations.html#code_block)
|
||||
> *didSet从句* → [*属性(Attributes)集*](..\chapter3\06_Attributes.html#attributes) _可选_ **didSet** [*setter名称*](..\chapter3\05_Declarations.html#setter_name) _可选_ [*代码块*](..\chapter3\05_Declarations.html#code_block)
|
||||
|
||||
<!-- -->
|
||||
|
||||
> 类型别名声明语法
|
||||
> *类型别名声明* → [*类型别名头(Head)*](..\chapter3\05_Declarations.html#typealias_head) [*类型别名赋值*](..\chapter3\05_Declarations.html#typealias_assignment)
|
||||
> *类型别名头(Head)* → **typealias** [*类型别名名称*](..\chapter3\05_Declarations.html#typealias_name)
|
||||
> *类型别名头(Head)* → [*属性*](TODO) _可选_ [*访问级别修改符(access-level-modifier)*](TODO) **typealias** [*类型别名名称*](..\chapter3\05_Declarations.html#typealias_name)
|
||||
> *类型别名名称* → [*标识符*](..\chapter3\02_Lexical_Structure.html#identifier)
|
||||
> *类型别名赋值* → **=** [*类型*](..\chapter3\03_Types.html#type)
|
||||
|
||||
<!-- -->
|
||||
|
||||
> 函数声明语法
|
||||
> *函数声明* → [*函数头*](..\chapter3\05_Declarations.html#function_head) [*函数名*](..\chapter3\05_Declarations.html#function_name) [*泛型参数子句*](GenericParametersAndArguments.html#generic_parameter_clause) _可选_ [*函数签名(Signature)*](..\chapter3\05_Declarations.html#function_signature) [*函数体*](..\chapter3\05_Declarations.html#function_body)
|
||||
> *函数头* → [*特性(Attributes)列表*](..\chapter3\06_Attributes.html#attributes) _可选_ [*声明描述符(Specifiers)列表*](..\chapter3\05_Declarations.html#declaration_specifiers) _可选_ **func**
|
||||
> *函数声明* → [*函数头*](..\chapter3\05_Declarations.html#function_head) [*函数名*](..\chapter3\05_Declarations.html#function_name) [*泛型参数从句*](GenericParametersAndArguments.html#generic_parameter_clause) _可选_ [*函数签名(Signature)*](..\chapter3\05_Declarations.html#function_signature) [*函数体*](..\chapter3\05_Declarations.html#function_body)
|
||||
> *函数头* → [*属性(Attributes)集*](..\chapter3\06_Attributes.html#attributes) _可选_ [*声明描述符(Specifiers)集*](..\chapter3\05_Declarations.html#declaration_specifiers) _可选_ **func**
|
||||
> *函数名* → [*标识符*](..\chapter3\02_Lexical_Structure.html#identifier) | [*运算符*](..\chapter3\02_Lexical_Structure.html#operator)
|
||||
> *函数签名(Signature)* → [*parameter-clauses*](..\chapter3\05_Declarations.html#parameter_clauses) [*函数结果*](..\chapter3\05_Declarations.html#function_result) _可选_
|
||||
> *函数结果* → **->** [*特性(Attributes)列表*](..\chapter3\06_Attributes.html#attributes) _可选_ [*类型*](..\chapter3\03_Types.html#type)
|
||||
> *函数签名(Signature)* → [*parameter-clauses*](..\chapter3\05_Declarations.html#parameter_clauses) **throws** _可选_ [*函数结果*](..\chapter3\05_Declarations.html#function_result) _可选_
|
||||
|
||||
> *函数签名(Signature)* → [*parameter-clauses*](..\chapter3\05_Declarations.html#parameter_clauses) **rethrows** [*函数结果*](..\chapter3\05_Declarations.html#function_result) _可选_
|
||||
> *函数结果* → **->** [*属性(Attributes)集*](..\chapter3\06_Attributes.html#attributes) _可选_ [*类型*](..\chapter3\03_Types.html#type)
|
||||
> *函数体* → [*代码块*](..\chapter3\05_Declarations.html#code_block)
|
||||
> *parameter-clauses* → [*参数子句*](..\chapter3\05_Declarations.html#parameter_clause) [*parameter-clauses*](..\chapter3\05_Declarations.html#parameter_clauses) _可选_
|
||||
> *参数子句* → **(** **)** | **(** [*参数列表*](..\chapter3\05_Declarations.html#parameter_list) **...** _可选_ **)**
|
||||
> *参数列表* → [*参数*](..\chapter3\05_Declarations.html#parameter) | [*参数*](..\chapter3\05_Declarations.html#parameter) **,** [*参数列表*](..\chapter3\05_Declarations.html#parameter_list)
|
||||
> *参数* → **inout** _可选_ **let** _可选_ **#** _可选_ [*参数名*](..\chapter3\05_Declarations.html#parameter_name) [*本地参数名*](..\chapter3\05_Declarations.html#local_parameter_name) _可选_ [*类型注解*](..\chapter3\03_Types.html#type_annotation) [*默认参数子句*](..\chapter3\05_Declarations.html#default_argument_clause) _可选_
|
||||
> *参数* → **inout** _可选_ **var** **#** _可选_ [*参数名*](..\chapter3\05_Declarations.html#parameter_name) [*本地参数名*](..\chapter3\05_Declarations.html#local_parameter_name) _可选_ [*类型注解*](..\chapter3\03_Types.html#type_annotation) [*默认参数子句*](..\chapter3\05_Declarations.html#default_argument_clause) _可选_
|
||||
> *参数* → [*特性(Attributes)列表*](..\chapter3\06_Attributes.html#attributes) _可选_ [*类型*](..\chapter3\03_Types.html#type)
|
||||
> *参数名* → [*标识符*](..\chapter3\02_Lexical_Structure.html#identifier) | **_**
|
||||
> *参数从句* → [*参数从句*](..\chapter3\05_Declarations.html#parameter_clause) [*parameter-clauses*](..\chapter3\05_Declarations.html#parameter_clauses) _可选_
|
||||
> *参数从句* → **(** **)** | **(** [*参数集*](..\chapter3\05_Declarations.html#parameter_list) **...** _可选_ **)**
|
||||
> *参数集* → [*参数*](..\chapter3\05_Declarations.html#parameter) | [*参数*](..\chapter3\05_Declarations.html#parameter) **,** [*参数集*](..\chapter3\05_Declarations.html#parameter_list)
|
||||
> *参数* → **inout** _可选_ **let** _可选_ [*外部参数名*](..\chapter3\05_Declarations.html#parameter_name) _可选_ [*本地参数名*](..\chapter3\05_Declarations.html#local_parameter_name) _可选_ [*类型注解*](..\chapter3\03_Types.html#type_annotation) [*默认参数从句*](..\chapter3\05_Declarations.html#default_argument_clause) _可选_
|
||||
> *参数* → **inout** _可选_ **var** [*外部参数名*](..\chapter3\05_Declarations.html#parameter_name) [*本地参数名*](..\chapter3\05_Declarations.html#local_parameter_name) _可选_ [*类型注解*](..\chapter3\03_Types.html#type_annotation) [*默认参数从句*](..\chapter3\05_Declarations.html#default_argument_clause) _可选_
|
||||
> *参数* → [*属性(Attributes)集*](..\chapter3\06_Attributes.html#attributes) _可选_ [*类型*](..\chapter3\03_Types.html#type)
|
||||
> *外部参数名* → [*标识符*](..\chapter3\02_Lexical_Structure.html#identifier) | **_**
|
||||
> *本地参数名* → [*标识符*](..\chapter3\02_Lexical_Structure.html#identifier) | **_**
|
||||
> *默认参数子句* → **=** [*表达式*](..\chapter3\04_Expressions.html#expression)
|
||||
> *默认参数从句* → **=** [*表达式*](..\chapter3\04_Expressions.html#expression)
|
||||
|
||||
<!-- -->
|
||||
|
||||
> 枚举声明语法
|
||||
> *枚举声明* → [*特性(Attributes)列表*](..\chapter3\06_Attributes.html#attributes) _可选_ [*联合式枚举*](..\chapter3\05_Declarations.html#union_style_enum) | [*特性(Attributes)列表*](..\chapter3\06_Attributes.html#attributes) _可选_ [*原始值式枚举*](..\chapter3\05_Declarations.html#raw_value_style_enum)
|
||||
> *联合式枚举* → [*枚举名*](..\chapter3\05_Declarations.html#enum_name) [*泛型参数子句*](GenericParametersAndArguments.html#generic_parameter_clause) _可选_ **{** [*union-style-enum-members*](..\chapter3\05_Declarations.html#union_style_enum_members) _可选_ **}**
|
||||
> *union-style-enum-members* → [*union-style-enum-member*](..\chapter3\05_Declarations.html#union_style_enum_member) [*union-style-enum-members*](..\chapter3\05_Declarations.html#union_style_enum_members) _可选_
|
||||
> *union-style-enum-member* → [*声明*](..\chapter3\05_Declarations.html#declaration) | [*联合式(Union Style)的枚举case子句*](..\chapter3\05_Declarations.html#union_style_enum_case_clause)
|
||||
> *联合式(Union Style)的枚举case子句* → [*特性(Attributes)列表*](..\chapter3\06_Attributes.html#attributes) _可选_ **case** [*联合式(Union Style)的枚举case列表*](..\chapter3\05_Declarations.html#union_style_enum_case_list)
|
||||
> *联合式(Union Style)的枚举case列表* → [*联合式(Union Style)的case*](..\chapter3\05_Declarations.html#union_style_enum_case) | [*联合式(Union Style)的case*](..\chapter3\05_Declarations.html#union_style_enum_case) **,** [*联合式(Union Style)的枚举case列表*](..\chapter3\05_Declarations.html#union_style_enum_case_list)
|
||||
> *联合式(Union Style)的case* → [*枚举的case名*](..\chapter3\05_Declarations.html#enum_case_name) [*元组类型*](..\chapter3\03_Types.html#tuple_type) _可选_
|
||||
> *枚举声明* → [*属性(Attributes)集*](..\chapter3\06_Attributes.html#attributes) _可选_ [*访问级别修改器(access-level-modifier)*](TODO) _可选_ [*联合式枚举*](..\chapter3\05_Declarations.html#union_style_enum)
|
||||
|
||||
> *枚举声明* → [*属性(Attributes)集*](..\chapter3\06_Attributes.html#attributes) _可选_ [*访问级别修改器(access-level-modifier)*](TODO) _可选_ [*原始值式枚举(raw-value-style-enum)*](TODO)
|
||||
|
||||
> *联合式枚举* → **enum** [*枚举名*](..\chapter3\05_Declarations.html#enum_name) [*泛型参数从句*](GenericParametersAndArguments.html#generic_parameter_clause) _可选_ [*类型继承从句(type-inheritance-clause)*](TODO) _可选_ **{** [*联合样式枚举成员*](..\chapter3\05_Declarations.html#union_style_enum_members) _可选_ **}**
|
||||
|
||||
> *联合样式枚举成员* → [*union-style-enum-member*](..\chapter3\05_Declarations.html#union_style_enum_member) [*联合样式枚举成员*](..\chapter3\05_Declarations.html#union_style_enum_members) _可选_
|
||||
|
||||
> *联合样式枚举成员* → [*声明*](..\chapter3\05_Declarations.html#declaration) | [*联合式(Union Style)的枚举case从句*](..\chapter3\05_Declarations.html#union_style_enum_case_clause)
|
||||
|
||||
> *联合式(Union Style)的枚举case从句* → [*属性(Attributes)集*](..\chapter3\06_Attributes.html#attributes) _可选_ **case** [*联合式(Union Style)的枚举case集*](..\chapter3\05_Declarations.html#union_style_enum_case_list)
|
||||
> *联合式(Union Style)的枚举case集* → [*联合式(Union Style)的case*](..\chapter3\05_Declarations.html#union_style_enum_case) | [*联合式(Union Style)的case*](..\chapter3\05_Declarations.html#union_style_enum_case) **,** [*联合式(Union Style)的枚举case集*](..\chapter3\05_Declarations.html#union_style_enum_case_list)
|
||||
> *联合式(Union Style)的枚举case* → [*枚举的case名*](..\chapter3\05_Declarations.html#enum_case_name) [*元组类型*](..\chapter3\03_Types.html#tuple_type) _可选_
|
||||
> *枚举名* → [*标识符*](..\chapter3\02_Lexical_Structure.html#identifier)
|
||||
> *枚举的case名* → [*标识符*](..\chapter3\02_Lexical_Structure.html#identifier)
|
||||
> *原始值式枚举* → [*枚举名*](..\chapter3\05_Declarations.html#enum_name) [*泛型参数子句*](GenericParametersAndArguments.html#generic_parameter_clause) _可选_ **:** [*类型标识*](..\chapter3\03_Types.html#type_identifier) **{** [*原始值式枚举成员列表*](..\chapter3\05_Declarations.html#raw_value_style_enum_members) _可选_ **}**
|
||||
> *原始值式枚举成员列表* → [*原始值式枚举成员*](..\chapter3\05_Declarations.html#raw_value_style_enum_member) [*原始值式枚举成员列表*](..\chapter3\05_Declarations.html#raw_value_style_enum_members) _可选_
|
||||
> *原始值式枚举成员* → [*声明*](..\chapter3\05_Declarations.html#declaration) | [*原始值式枚举case子句*](..\chapter3\05_Declarations.html#raw_value_style_enum_case_clause)
|
||||
> *原始值式枚举case子句* → [*特性(Attributes)列表*](..\chapter3\06_Attributes.html#attributes) _可选_ **case** [*原始值式枚举case列表*](..\chapter3\05_Declarations.html#raw_value_style_enum_case_list)
|
||||
> *原始值式枚举case列表* → [*原始值式枚举case*](..\chapter3\05_Declarations.html#raw_value_style_enum_case) | [*原始值式枚举case*](..\chapter3\05_Declarations.html#raw_value_style_enum_case) **,** [*原始值式枚举case列表*](..\chapter3\05_Declarations.html#raw_value_style_enum_case_list)
|
||||
> *原始值式枚举* → **enum** [*枚举名*](..\chapter3\05_Declarations.html#enum_name) [*泛型参数从句*](GenericParametersAndArguments.html#generic_parameter_clause) _可选_ **:** [*类型标识*](..\chapter3\03_Types.html#type_identifier) **{** [*原始值式枚举成员集*](..\chapter3\05_Declarations.html#raw_value_style_enum_members) _可选_ **}**
|
||||
> *原始值式枚举成员集* → [*原始值式枚举成员*](..\chapter3\05_Declarations.html#raw_value_style_enum_member) [*原始值式枚举成员集*](..\chapter3\05_Declarations.html#raw_value_style_enum_members) _可选_
|
||||
> *原始值式枚举成员* → [*声明*](..\chapter3\05_Declarations.html#declaration) | [*原始值式枚举case从句*](..\chapter3\05_Declarations.html#raw_value_style_enum_case_clause)
|
||||
> *原始值式枚举case从句* → [*属性(Attributes)集*](..\chapter3\06_Attributes.html#attributes) _可选_ **case** [*原始值式枚举case集*](..\chapter3\05_Declarations.html#raw_value_style_enum_case_list)
|
||||
> *原始值式枚举case集* → [*原始值式枚举case*](..\chapter3\05_Declarations.html#raw_value_style_enum_case) | [*原始值式枚举case*](..\chapter3\05_Declarations.html#raw_value_style_enum_case) **,** [*原始值式枚举case集*](..\chapter3\05_Declarations.html#raw_value_style_enum_case_list)
|
||||
> *原始值式枚举case* → [*枚举的case名*](..\chapter3\05_Declarations.html#enum_case_name) [*原始值赋值*](..\chapter3\05_Declarations.html#raw_value_assignment) _可选_
|
||||
> *原始值赋值* → **=** [*字面量*](..\chapter3\02_Lexical_Structure.html#literal)
|
||||
> *原始值字面量(raw-value-literal)* → [*数值字面量*](TODO) | [*字符串字面量*](TODO) | [*布尔字面量*](TODO)
|
||||
|
||||
<!-- -->
|
||||
|
||||
> 结构体声明语法
|
||||
> *结构体声明* → [*特性(Attributes)列表*](..\chapter3\06_Attributes.html#attributes) _可选_ **struct** [*结构体名称*](..\chapter3\05_Declarations.html#struct_name) [*泛型参数子句*](GenericParametersAndArguments.html#generic_parameter_clause) _可选_ [*类型继承子句*](..\chapter3\03_Types.html#type_inheritance_clause) _可选_ [*结构体主体*](..\chapter3\05_Declarations.html#struct_body)
|
||||
> *结构体声明* → [*属性(Attributes)集*](..\chapter3\06_Attributes.html#attributes) _可选_ [*访问级别修改器(access-level-modifier)*](TODO) _可选_ **struct** [*结构体名称*](..\chapter3\05_Declarations.html#struct_name) [*泛型参数从句*](GenericParametersAndArguments.html#generic_parameter_clause) _可选_ [*类型继承从句*](..\chapter3\03_Types.html#type_inheritance_clause) _可选_ [*结构体主体*](..\chapter3\05_Declarations.html#struct_body)
|
||||
> *结构体名称* → [*标识符*](..\chapter3\02_Lexical_Structure.html#identifier)
|
||||
> *结构体主体* → **{** [*声明(Declarations)列表*](..\chapter3\05_Declarations.html#declarations) _可选_ **}**
|
||||
> *结构体主体* → **{** [*声明(Declarations)集*](..\chapter3\05_Declarations.html#declarations) _可选_ **}**
|
||||
|
||||
<!-- -->
|
||||
|
||||
> 类声明语法
|
||||
> *类声明* → [*特性(Attributes)列表*](..\chapter3\06_Attributes.html#attributes) _可选_ **class** [*类名*](..\chapter3\05_Declarations.html#class_name) [*泛型参数子句*](GenericParametersAndArguments.html#generic_parameter_clause) _可选_ [*类型继承子句*](..\chapter3\03_Types.html#type_inheritance_clause) _可选_ [*类主体*](..\chapter3\05_Declarations.html#class_body)
|
||||
> *类声明* → [*属性(Attributes)集*](..\chapter3\06_Attributes.html#attributes) _可选_ [*访问级别修改器(access-level-modifier)*](TODO) **class** [*类名*](..\chapter3\05_Declarations.html#class_name) [*泛型参数从句*](GenericParametersAndArguments.html#generic_parameter_clause) _可选_ [*类型继承从句*](..\chapter3\03_Types.html#type_inheritance_clause) _可选_ [*类主体*](..\chapter3\05_Declarations.html#class_body)
|
||||
> *类名* → [*标识符*](..\chapter3\02_Lexical_Structure.html#identifier)
|
||||
> *类主体* → **{** [*声明(Declarations)列表*](..\chapter3\05_Declarations.html#declarations) _可选_ **}**
|
||||
> *类主体* → **{** [*声明(Declarations)集*](..\chapter3\05_Declarations.html#declarations) _可选_ **}**
|
||||
|
||||
<!-- -->
|
||||
|
||||
> 协议(Protocol)声明语法
|
||||
> *协议声明* → [*特性(Attributes)列表*](..\chapter3\06_Attributes.html#attributes) _可选_ **protocol** [*协议名*](..\chapter3\05_Declarations.html#protocol_name) [*类型继承子句*](..\chapter3\03_Types.html#type_inheritance_clause) _可选_ [*协议主体*](..\chapter3\05_Declarations.html#protocol_body)
|
||||
> *协议声明* → [*属性(Attributes)集*](..\chapter3\06_Attributes.html#attributes) _可选_[*访问级别修改器(access-level-modifier)*](TODO) **protocol** [*协议名*](..\chapter3\05_Declarations.html#protocol_name) [*类型继承从句*](..\chapter3\03_Types.html#type_inheritance_clause) _可选_ [*协议主体*](..\chapter3\05_Declarations.html#protocol_body)
|
||||
> *协议名* → [*标识符*](..\chapter3\02_Lexical_Structure.html#identifier)
|
||||
> *协议主体* → **{** [*协议成员声明(Declarations)列表*](..\chapter3\05_Declarations.html#protocol_member_declarations) _可选_ **}**
|
||||
> *协议主体* → **{** [*协议成员声明(Declarations)集*](..\chapter3\05_Declarations.html#protocol_member_declarations) _可选_ **}**
|
||||
> *协议成员声明* → [*协议属性声明*](..\chapter3\05_Declarations.html#protocol_property_declaration)
|
||||
> *协议成员声明* → [*协议方法声明*](..\chapter3\05_Declarations.html#protocol_method_declaration)
|
||||
> *协议成员声明* → [*协议构造器声明*](..\chapter3\05_Declarations.html#protocol_initializer_declaration)
|
||||
> *协议成员声明* → [*协议下标脚本声明*](..\chapter3\05_Declarations.html#protocol_subscript_declaration)
|
||||
> *协议成员声明* → [*协议关联类型声明*](..\chapter3\05_Declarations.html#protocol_associated_type_declaration)
|
||||
> *协议成员声明(Declarations)列表* → [*协议成员声明*](..\chapter3\05_Declarations.html#protocol_member_declaration) [*协议成员声明(Declarations)列表*](..\chapter3\05_Declarations.html#protocol_member_declarations) _可选_
|
||||
> *协议成员声明(Declarations)集* → [*协议成员声明*](..\chapter3\05_Declarations.html#protocol_member_declaration) [*协议成员声明(Declarations)集*](..\chapter3\05_Declarations.html#protocol_member_declarations) _可选_
|
||||
|
||||
<!-- -->
|
||||
|
||||
@ -296,12 +381,12 @@ _________________
|
||||
<!-- -->
|
||||
|
||||
> 协议方法声明语法
|
||||
> *协议方法声明* → [*函数头*](..\chapter3\05_Declarations.html#function_head) [*函数名*](..\chapter3\05_Declarations.html#function_name) [*泛型参数子句*](GenericParametersAndArguments.html#generic_parameter_clause) _可选_ [*函数签名(Signature)*](..\chapter3\05_Declarations.html#function_signature)
|
||||
> *协议方法声明* → [*函数头*](..\chapter3\05_Declarations.html#function_head) [*函数名*](..\chapter3\05_Declarations.html#function_name) [*泛型参数从句*](GenericParametersAndArguments.html#generic_parameter_clause) _可选_ [*函数签名(Signature)*](..\chapter3\05_Declarations.html#function_signature)
|
||||
|
||||
<!-- -->
|
||||
|
||||
> 协议构造器声明语法
|
||||
> *协议构造器声明* → [*构造器头(Head)*](..\chapter3\05_Declarations.html#initializer_head) [*泛型参数子句*](GenericParametersAndArguments.html#generic_parameter_clause) _可选_ [*参数子句*](..\chapter3\05_Declarations.html#parameter_clause)
|
||||
> *协议构造器声明* → [*构造器头(Head)*](..\chapter3\05_Declarations.html#initializer_head) [*泛型参数从句*](GenericParametersAndArguments.html#generic_parameter_clause) _可选_ [*参数从句*](..\chapter3\05_Declarations.html#parameter_clause)
|
||||
|
||||
<!-- -->
|
||||
|
||||
@ -311,25 +396,29 @@ _________________
|
||||
<!-- -->
|
||||
|
||||
> 协议关联类型声明语法
|
||||
> *协议关联类型声明* → [*类型别名头(Head)*](..\chapter3\05_Declarations.html#typealias_head) [*类型继承子句*](..\chapter3\03_Types.html#type_inheritance_clause) _可选_ [*类型别名赋值*](..\chapter3\05_Declarations.html#typealias_assignment) _可选_
|
||||
> *协议关联类型声明* → [*类型别名头(Head)*](..\chapter3\05_Declarations.html#typealias_head) [*类型继承从句*](..\chapter3\03_Types.html#type_inheritance_clause) _可选_ [*类型别名赋值*](..\chapter3\05_Declarations.html#typealias_assignment) _可选_
|
||||
|
||||
<!-- -->
|
||||
|
||||
> 构造器声明语法
|
||||
> *构造器声明* → [*构造器头(Head)*](..\chapter3\05_Declarations.html#initializer_head) [*泛型参数子句*](GenericParametersAndArguments.html#generic_parameter_clause) _可选_ [*参数子句*](..\chapter3\05_Declarations.html#parameter_clause) [*构造器主体*](..\chapter3\05_Declarations.html#initializer_body)
|
||||
> *构造器头(Head)* → [*特性(Attributes)列表*](..\chapter3\06_Attributes.html#attributes) _可选_ **convenience** _可选_ **init**
|
||||
> *构造器声明* → [*构造器头(Head)*](..\chapter3\05_Declarations.html#initializer_head) [*泛型参数从句*](GenericParametersAndArguments.html#generic_parameter_clause) _可选_ [*参数从句*](..\chapter3\05_Declarations.html#parameter_clause) [*构造器主体*](..\chapter3\05_Declarations.html#initializer_body)
|
||||
> *构造器头(Head)* → [*属性(Attributes)集*](..\chapter3\06_Attributes.html#attributes) _可选_ [*声明修改器集(declaration-modifiers)*](TODO) _可选_ **init**
|
||||
> *构造器头(Head)* → [*属性(Attributes)集*](..\chapter3\06_Attributes.html#attributes) _可选_ [*声明修改器集(declaration-modifiers)*](TODO) _可选_ **init ?**
|
||||
|
||||
> *构造器头(Head)* → [*属性(Attributes)集*](..\chapter3\06_Attributes.html#attributes) _可选_ [*声明修改器集(declaration-modifiers)*](TODO) _可选_ **init !**
|
||||
|
||||
> *构造器主体* → [*代码块*](..\chapter3\05_Declarations.html#code_block)
|
||||
|
||||
<!-- -->
|
||||
|
||||
> 析构器声明语法
|
||||
> *析构器声明* → [*特性(Attributes)列表*](..\chapter3\06_Attributes.html#attributes) _可选_ **deinit** [*代码块*](..\chapter3\05_Declarations.html#code_block)
|
||||
> *析构器声明* → [*属性(Attributes)集*](..\chapter3\06_Attributes.html#attributes) _可选_ **deinit** [*代码块*](..\chapter3\05_Declarations.html#code_block)
|
||||
|
||||
<!-- -->
|
||||
|
||||
> 扩展(Extension)声明语法
|
||||
> *扩展声明* → **extension** [*类型标识*](..\chapter3\03_Types.html#type_identifier) [*类型继承子句*](..\chapter3\03_Types.html#type_inheritance_clause) _可选_ [*extension-body*](..\chapter3\05_Declarations.html#extension_body)
|
||||
> *extension-body* → **{** [*声明(Declarations)列表*](..\chapter3\05_Declarations.html#declarations) _可选_ **}**
|
||||
> *扩展声明* → [*访问级别修改器*](TODO) _可选_ **extension** [*类型标识*](..\chapter3\03_Types.html#type_identifier) [*类型继承从句*](..\chapter3\03_Types.html#type_inheritance_clause) _可选_ [*extension-body*](..\chapter3\05_Declarations.html#extension_body)
|
||||
> *extension-body* → **{** [*声明(Declarations)集*](..\chapter3\05_Declarations.html#declarations) _可选_ **}**
|
||||
|
||||
<!-- -->
|
||||
|
||||
@ -337,32 +426,51 @@ _________________
|
||||
> *下标脚本声明* → [*下标脚本头(Head)*](..\chapter3\05_Declarations.html#subscript_head) [*下标脚本结果(Result)*](..\chapter3\05_Declarations.html#subscript_result) [*代码块*](..\chapter3\05_Declarations.html#code_block)
|
||||
> *下标脚本声明* → [*下标脚本头(Head)*](..\chapter3\05_Declarations.html#subscript_head) [*下标脚本结果(Result)*](..\chapter3\05_Declarations.html#subscript_result) [*getter-setter块*](..\chapter3\05_Declarations.html#getter_setter_block)
|
||||
> *下标脚本声明* → [*下标脚本头(Head)*](..\chapter3\05_Declarations.html#subscript_head) [*下标脚本结果(Result)*](..\chapter3\05_Declarations.html#subscript_result) [*getter-setter关键字(Keyword)块*](..\chapter3\05_Declarations.html#getter_setter_keyword_block)
|
||||
> *下标脚本头(Head)* → [*特性(Attributes)列表*](..\chapter3\06_Attributes.html#attributes) _可选_ **subscript** [*参数子句*](..\chapter3\05_Declarations.html#parameter_clause)
|
||||
> *下标脚本结果(Result)* → **->** [*特性(Attributes)列表*](..\chapter3\06_Attributes.html#attributes) _可选_ [*类型*](..\chapter3\03_Types.html#type)
|
||||
> *下标脚本头(Head)* → [*属性(Attributes)集*](..\chapter3\06_Attributes.html#attributes) _可选_ [*声明修改器(declaration-modifiers)*](TODO) _可选_ **subscript** [*参数从句*](..\chapter3\05_Declarations.html#parameter_clause)
|
||||
> *下标脚本结果(Result)* → **->** [*属性(Attributes)集*](..\chapter3\06_Attributes.html#attributes) _可选_ [*类型*](..\chapter3\03_Types.html#type)
|
||||
|
||||
<!-- -->
|
||||
|
||||
> 运算符声明语法
|
||||
> *运算符声明* → [*前置运算符声明*](..\chapter3\05_Declarations.html#prefix_operator_declaration) | [*后置运算符声明*](..\chapter3\05_Declarations.html#postfix_operator_declaration) | [*中置运算符声明*](..\chapter3\05_Declarations.html#infix_operator_declaration)
|
||||
> *前置运算符声明* → **运算符** **prefix** [*运算符*](..\chapter3\02_Lexical_Structure.html#operator) **{** **}**
|
||||
> *后置运算符声明* → **运算符** **postfix** [*运算符*](..\chapter3\02_Lexical_Structure.html#operator) **{** **}**
|
||||
> *中置运算符声明* → **运算符** **infix** [*运算符*](..\chapter3\02_Lexical_Structure.html#operator) **{** [*中置运算符属性*](..\chapter3\05_Declarations.html#infix_operator_attributes) _可选_ **}**
|
||||
> *中置运算符属性* → [*优先级子句*](..\chapter3\05_Declarations.html#precedence_clause) _可选_ [*结和性子句*](..\chapter3\05_Declarations.html#associativity_clause) _可选_
|
||||
> *优先级子句* → **precedence** [*优先级水平*](..\chapter3\05_Declarations.html#precedence_level)
|
||||
> *优先级水平* → 数值 0 到 255
|
||||
> *结和性子句* → **associativity** [*结和性*](..\chapter3\05_Declarations.html#associativity)
|
||||
> *前置运算符声明* → **prefix** **运算符** [*运算符*](..\chapter3\02_Lexical_Structure.html#operator) **{** **}**
|
||||
> *后置运算符声明* → **postfix** **运算符** [*运算符*](..\chapter3\02_Lexical_Structure.html#operator) **{** **}**
|
||||
> *中置运算符声明* → **infix** **运算符** [*运算符*](..\chapter3\02_Lexical_Structure.html#operator) **{** [*中置运算符属性集*](..\chapter3\05_Declarations.html#infix_operator_attributes) _可选_ **}**
|
||||
> *中置运算符属性集* → [*优先级从句*](..\chapter3\05_Declarations.html#precedence_clause) _可选_ [*结和性从句*](..\chapter3\05_Declarations.html#associativity_clause) _可选_
|
||||
> *优先级从句* → **precedence** [*优先级水平*](..\chapter3\05_Declarations.html#precedence_level)
|
||||
> *优先级水平* → 数值 0 到 255,首末项包括在内
|
||||
> *结和性从句* → **associativity** [*结和性*](..\chapter3\05_Declarations.html#associativity)
|
||||
> *结和性* → **left** | **right** | **none**
|
||||
|
||||
<!-- -->
|
||||
声明修改器语法
|
||||
> *声明修改器* → **类** | **便捷(convenience)** | **动态(dynamic)** | **final** | **中置(infix)** | **lazy** | **可变(mutating)** | **不可变(nonmutating)** | **可选(optional)** | **改写(override)** | **后置** | **前置** | **required** | **static** | **unowned** | **unowned(safe)** | **unowned(unsafe)** | **弱(weak)**
|
||||
|
||||
> *声明修改器* → [*访问级别声明器(access-level-modifier)*](TODO)
|
||||
|
||||
> *声明修改集* → [*声明修改器*](TODO) [*声明修改器集*](TODO) _可选_
|
||||
|
||||
> *访问级别修改器* → **内部的** | **内部的(set)**
|
||||
|
||||
> *访问级别修改器* → **私有的** | **私有的(set)**
|
||||
|
||||
> *访问级别修改器* → **公共的**
|
||||
| **公共的(set)**
|
||||
|
||||
> *访问级别修改器集* →[*访问级别修改器*](TODO) [*访问级别修改器集*](TODO) _可选_
|
||||
|
||||
<a name="patterns"></a>
|
||||
## 模式
|
||||
|
||||
> 模式(Patterns) 语法
|
||||
> *模式* → [*通配符模式*](..\chapter3\07_Patterns.html#wildcard_pattern) [*类型注解*](..\chapter3\03_Types.html#type_annotation) _可选_
|
||||
> *模式* → [*标识符模式*](..\chapter3\07_Patterns.html#identifier_pattern) [*类型注解*](..\chapter3\03_Types.html#type_annotati(Value Binding)on) _可选_
|
||||
> *模式* → [*标识符模式*](..\chapter3\07_Patterns.html#identifier_pattern) [*类型注解*](..\chapter3\03_Types.html#type_annotati Value Bindingon ) _可选_
|
||||
> *模式* → [*值绑定模式*](..\chapter3\07_Patterns.html#value_binding_pattern)
|
||||
> *模式* → [*元组模式*](..\chapter3\07_Patterns.html#tuple_pattern) [*类型注解*](..\chapter3\03_Types.html#type_annotation) _可选_
|
||||
> *模式* → [*enum-case-pattern*](..\chapter3\07_Patterns.html#enum_case_pattern)
|
||||
> *模式* → [*type-casting-pattern*](..\chapter3\07_Patterns.html#type_casting_pattern)
|
||||
|
||||
> *模式* → [*枚举个例模式*](..\chapter3\07_Patterns.html#enum_case_pattern)
|
||||
> *模式* → [*可选模式*](TODO)
|
||||
> *模式* → [*类型转换模式*](..\chapter3\07_Patterns.html#type_casting_pattern)
|
||||
> *模式* → [*表达式模式*](..\chapter3\07_Patterns.html#expression_pattern)
|
||||
|
||||
<!-- -->
|
||||
@ -383,8 +491,8 @@ _________________
|
||||
<!-- -->
|
||||
|
||||
> 元组模式语法
|
||||
> *元组模式* → **(** [*元组模式元素列表*](..\chapter3\07_Patterns.html#tuple_pattern_element_list) _可选_ **)**
|
||||
> *元组模式元素列表* → [*元组模式元素*](..\chapter3\07_Patterns.html#tuple_pattern_element) | [*元组模式元素*](..\chapter3\07_Patterns.html#tuple_pattern_element) **,** [*元组模式元素列表*](..\chapter3\07_Patterns.html#tuple_pattern_element_list)
|
||||
> *元组模式* → **(** [*元组模式元素集*](..\chapter3\07_Patterns.html#tuple_pattern_element_list) _可选_ **)**
|
||||
> *元组模式元素集* → [*元组模式元素*](..\chapter3\07_Patterns.html#tuple_pattern_element) | [*元组模式元素*](..\chapter3\07_Patterns.html#tuple_pattern_element) **,** [*元组模式元素集*](..\chapter3\07_Patterns.html#tuple_pattern_element_list)
|
||||
> *元组模式元素* → [*模式*](..\chapter3\07_Patterns.html#pattern)
|
||||
|
||||
<!-- -->
|
||||
@ -392,10 +500,15 @@ _________________
|
||||
> 枚举用例模式语法
|
||||
> *enum-case-pattern* → [*类型标识*](..\chapter3\03_Types.html#type_identifier) _可选_ **.** [*枚举的case名*](..\chapter3\05_Declarations.html#enum_case_name) [*元组模式*](..\chapter3\07_Patterns.html#tuple_pattern) _可选_
|
||||
|
||||
<!-- -->
|
||||
> 可选模式语法
|
||||
> *可选模式* → [*识别符模式*](TODO) **?**
|
||||
|
||||
|
||||
<!-- -->
|
||||
|
||||
> 类型转换模式语法
|
||||
> *type-casting-pattern* → [*is模式*](..\chapter3\07_Patterns.html#is_pattern) | [*as模式*](..\chapter3\07_Patterns.html#as_pattern)
|
||||
> *类型转换模式(type-casting-pattern)* → [*is模式*](..\chapter3\07_Patterns.html#is_pattern) | [*as模式*](..\chapter3\07_Patterns.html#as_pattern)
|
||||
> *is模式* → **is** [*类型*](..\chapter3\03_Types.html#type)
|
||||
> *as模式* → [*模式*](..\chapter3\07_Patterns.html#pattern) **as** [*类型*](..\chapter3\03_Types.html#type)
|
||||
|
||||
@ -405,17 +518,17 @@ _________________
|
||||
> *表达式模式* → [*表达式*](..\chapter3\04_Expressions.html#expression)
|
||||
|
||||
<a name="attributes"></a>
|
||||
## 特性
|
||||
## 属性
|
||||
|
||||
> 特性语法
|
||||
> *特色* → **@** [*特性名*](..\chapter3\06_Attributes.html#attribute_name) [*特性参数子句*](..\chapter3\06_Attributes.html#attribute_argument_clause) _可选_
|
||||
> *特性名* → [*标识符*](..\chapter3\02_Lexical_Structure.html#identifier)
|
||||
> *特性参数子句* → **(** [*平衡令牌列表*](..\chapter3\06_Attributes.html#balanced_tokens) _可选_ **)**
|
||||
> *特性(Attributes)列表* → [*特色*](..\chapter3\06_Attributes.html#attribute) [*特性(Attributes)列表*](..\chapter3\06_Attributes.html#attributes) _可选_
|
||||
> *平衡令牌列表* → [*平衡令牌*](..\chapter3\06_Attributes.html#balanced_token) [*平衡令牌列表*](..\chapter3\06_Attributes.html#balanced_tokens) _可选_
|
||||
> *平衡令牌* → **(** [*平衡令牌列表*](..\chapter3\06_Attributes.html#balanced_tokens) _可选_ **)**
|
||||
> *平衡令牌* → **[** [*平衡令牌列表*](..\chapter3\06_Attributes.html#balanced_tokens) _可选_ **]**
|
||||
> *平衡令牌* → **{** [*平衡令牌列表*](..\chapter3\06_Attributes.html#balanced_tokens) _可选_ **}**
|
||||
> 属性语法
|
||||
> *属性* → **@** [*属性名*](..\chapter3\06_Attributes.html#attribute_name) [*属性参数从句*](..\chapter3\06_Attributes.html#attribute_argument_clause) _可选_
|
||||
> *属性名* → [*标识符*](..\chapter3\02_Lexical_Structure.html#identifier)
|
||||
> *属性参数从句* → **(** [*平衡令牌集*](..\chapter3\06_Attributes.html#balanced_tokens) _可选_ **)**
|
||||
> *属性(Attributes)集* → [*属性*](..\chapter3\06_Attributes.html#attribute) [*属性(Attributes)集*](..\chapter3\06_Attributes.html#attributes) _可选_
|
||||
> *平衡令牌集* → [*平衡令牌*](..\chapter3\06_Attributes.html#balanced_token) [*平衡令牌集*](..\chapter3\06_Attributes.html#balanced_tokens) _可选_
|
||||
> *平衡令牌* → **(** [*平衡令牌集*](..\chapter3\06_Attributes.html#balanced_tokens) _可选_ **)**
|
||||
> *平衡令牌* → **[** [*平衡令牌集*](..\chapter3\06_Attributes.html#balanced_tokens) _可选_ **]**
|
||||
> *平衡令牌* → **{** [*平衡令牌集*](..\chapter3\06_Attributes.html#balanced_tokens) _可选_ **}**
|
||||
> *平衡令牌* → **任意标识符, 关键字, 字面量或运算符**
|
||||
> *平衡令牌* → **任意标点除了(, ), [, ], {, 或 }**
|
||||
|
||||
@ -423,8 +536,8 @@ _________________
|
||||
## 表达式
|
||||
|
||||
> 表达式语法
|
||||
> *表达式* → [*前置表达式*](..\chapter3\04_Expressions.html#prefix_expression) [*二元表达式列表*](..\chapter3\04_Expressions.html#binary_expressions) _可选_
|
||||
> *表达式列表* → [*表达式*](..\chapter3\04_Expressions.html#expression) | [*表达式*](..\chapter3\04_Expressions.html#expression) **,** [*表达式列表*](..\chapter3\04_Expressions.html#expression_list)
|
||||
> *表达式* → [*try-operator*](TODO) _可选_ [*前置表达式*](..\chapter3\04_Expressions.html#prefix_expression) [*二元表达式集*](..\chapter3\04_Expressions.html#binary_expressions) _可选_
|
||||
> *表达式集* → [*表达式*](..\chapter3\04_Expressions.html#expression) | [*表达式*](..\chapter3\04_Expressions.html#expression) **,** [*表达式集*](..\chapter3\04_Expressions.html#expression_list)
|
||||
|
||||
<!-- -->
|
||||
|
||||
@ -433,14 +546,19 @@ _________________
|
||||
> *前置表达式* → [*写入写出(in-out)表达式*](..\chapter3\04_Expressions.html#in_out_expression)
|
||||
> *写入写出(in-out)表达式* → **&** [*标识符*](..\chapter3\02_Lexical_Structure.html#identifier)
|
||||
|
||||
<!-- -->
|
||||
> try表达式语法
|
||||
> *try-operator* → **try** | **try !**
|
||||
|
||||
|
||||
<!-- -->
|
||||
|
||||
> 二元表达式语法
|
||||
> *二元表达式* → [*二元运算符*](..\chapter3\02_Lexical_Structure.html#binary_operator) [*前置表达式*](..\chapter3\04_Expressions.html#prefix_expression)
|
||||
> *二元表达式* → [*赋值运算符*](..\chapter3\04_Expressions.html#assignment_operator) [*前置表达式*](..\chapter3\04_Expressions.html#prefix_expression)
|
||||
> *二元表达式* → [*条件运算符*](..\chapter3\04_Expressions.html#conditional_operator) [*前置表达式*](..\chapter3\04_Expressions.html#prefix_expression)
|
||||
> *二元表达式* → [*赋值运算符*](..\chapter3\04_Expressions.html#assignment_operator) [*try运算符*](TODO) _可选_ [*前置表达式*](..\chapter3\04_Expressions.html#prefix_expression)
|
||||
> *二元表达式* → [*条件运算符*](..\chapter3\04_Expressions.html#conditional_operator) [*try运算符*](TODO) _可选_ [*前置表达式*](..\chapter3\04_Expressions.html#prefix_expression)
|
||||
> *二元表达式* → [*类型转换运算符*](..\chapter3\04_Expressions.html#type_casting_operator)
|
||||
> *二元表达式列表* → [*二元表达式*](..\chapter3\04_Expressions.html#binary_expression) [*二元表达式列表*](..\chapter3\04_Expressions.html#binary_expressions) _可选_
|
||||
> *二元表达式集* → [*二元表达式*](..\chapter3\04_Expressions.html#binary_expression) [*二元表达式集*](..\chapter3\04_Expressions.html#binary_expressions) _可选_
|
||||
|
||||
<!-- -->
|
||||
|
||||
@ -455,12 +573,20 @@ _________________
|
||||
<!-- -->
|
||||
|
||||
> 类型转换运算符语法
|
||||
> *类型转换运算符* → **is** [*类型*](..\chapter3\03_Types.html#type) | **as** **?** _可选_ [*类型*](..\chapter3\03_Types.html#type)
|
||||
> *类型转换运算符* → **is** [*类型*](..\chapter3\03_Types.html#type)
|
||||
|
||||
> *类型转换运算符* → **as** [*类型*](..\chapter3\03_Types.html#type)
|
||||
|
||||
> *类型转换运算符* → **as ?** [*类型*](..\chapter3\03_Types.html#type)
|
||||
|
||||
> *类型转换运算符* → **as !** [*类型*](..\chapter3\03_Types.html#type)
|
||||
|
||||
|
||||
|
||||
<!-- -->
|
||||
|
||||
> 主表达式语法
|
||||
> *主表达式* → [*标识符*](..\chapter3\02_Lexical_Structure.html#identifier) [*泛型参数子句*](GenericParametersAndArguments.html#generic_argument_clause) _可选_
|
||||
> *主表达式* → [*标识符*](..\chapter3\02_Lexical_Structure.html#identifier) [*泛型参数从句*](GenericParametersAndArguments.html#generic_argument_clause) _可选_
|
||||
> *主表达式* → [*字面量表达式*](..\chapter3\04_Expressions.html#literal_expression)
|
||||
> *主表达式* → [*self表达式*](..\chapter3\04_Expressions.html#self_expression)
|
||||
> *主表达式* → [*超类表达式*](..\chapter3\04_Expressions.html#superclass_expression)
|
||||
@ -475,11 +601,11 @@ _________________
|
||||
> *字面量表达式* → [*字面量*](..\chapter3\02_Lexical_Structure.html#literal)
|
||||
> *字面量表达式* → [*数组字面量*](..\chapter3\04_Expressions.html#array_literal) | [*字典字面量*](..\chapter3\04_Expressions.html#dictionary_literal)
|
||||
> *字面量表达式* → **__FILE__** | **__LINE__** | **__COLUMN__** | **__FUNCTION__**
|
||||
> *数组字面量* → **[** [*数组字面量项列表*](..\chapter3\04_Expressions.html#array_literal_items) _可选_ **]**
|
||||
> *数组字面量项列表* → [*数组字面量项*](..\chapter3\04_Expressions.html#array_literal_item) **,** _可选_ | [*数组字面量项*](..\chapter3\04_Expressions.html#array_literal_item) **,** [*数组字面量项列表*](..\chapter3\04_Expressions.html#array_literal_items)
|
||||
> *数组字面量* → **[** [*数组字面量项集*](..\chapter3\04_Expressions.html#array_literal_items) _可选_ **]**
|
||||
> *数组字面量项集* → [*数组字面量项*](..\chapter3\04_Expressions.html#array_literal_item) **,** _可选_ | [*数组字面量项*](..\chapter3\04_Expressions.html#array_literal_item) **,** [*数组字面量项集*](..\chapter3\04_Expressions.html#array_literal_items)
|
||||
> *数组字面量项* → [*表达式*](..\chapter3\04_Expressions.html#expression)
|
||||
> *字典字面量* → **[** [*字典字面量项列表*](..\chapter3\04_Expressions.html#dictionary_literal_items) **]** | **[** **:** **]**
|
||||
> *字典字面量项列表* → [*字典字面量项*](..\chapter3\04_Expressions.html#dictionary_literal_item) **,** _可选_ | [*字典字面量项*](..\chapter3\04_Expressions.html#dictionary_literal_item) **,** [*字典字面量项列表*](..\chapter3\04_Expressions.html#dictionary_literal_items)
|
||||
> *字典字面量* → **[** [*字典字面量项集*](..\chapter3\04_Expressions.html#dictionary_literal_items) **]** | **[** **:** **]**
|
||||
> *字典字面量项集* → [*字典字面量项*](..\chapter3\04_Expressions.html#dictionary_literal_item) **,** _可选_ | [*字典字面量项*](..\chapter3\04_Expressions.html#dictionary_literal_item) **,** [*字典字面量项集*](..\chapter3\04_Expressions.html#dictionary_literal_items)
|
||||
> *字典字面量项* → [*表达式*](..\chapter3\04_Expressions.html#expression) **:** [*表达式*](..\chapter3\04_Expressions.html#expression)
|
||||
|
||||
<!-- -->
|
||||
@ -502,12 +628,12 @@ _________________
|
||||
|
||||
> 闭包表达式语法
|
||||
> *闭包表达式* → **{** [*闭包签名(Signational)*](..\chapter3\04_Expressions.html#closure_signature) _可选_ [*多条语句(Statements)*](..\chapter3\10_Statements.html#statements) **}**
|
||||
> *闭包签名(Signational)* → [*参数子句*](..\chapter3\05_Declarations.html#parameter_clause) [*函数结果*](..\chapter3\05_Declarations.html#function_result) _可选_ **in**
|
||||
> *闭包签名(Signational)* → [*标识符列表*](..\chapter3\02_Lexical_Structure.html#identifier_list) [*函数结果*](..\chapter3\05_Declarations.html#function_result) _可选_ **in**
|
||||
> *闭包签名(Signational)* → [*捕获(Capature)列表*](..\chapter3\04_Expressions.html#capture_list) [*参数子句*](..\chapter3\05_Declarations.html#parameter_clause) [*函数结果*](..\chapter3\05_Declarations.html#function_result) _可选_ **in**
|
||||
> *闭包签名(Signational)* → [*捕获(Capature)列表*](..\chapter3\04_Expressions.html#capture_list) [*标识符列表*](..\chapter3\02_Lexical_Structure.html#identifier_list) [*函数结果*](..\chapter3\05_Declarations.html#function_result) _可选_ **in**
|
||||
> *闭包签名(Signational)* → [*捕获(Capature)列表*](..\chapter3\04_Expressions.html#capture_list) **in**
|
||||
> *捕获(Capature)列表* → **[** [*捕获(Capature)说明符*](..\chapter3\04_Expressions.html#capture_specifier) [*表达式*](..\chapter3\04_Expressions.html#expression) **]**
|
||||
> *闭包签名(Signational)* → [*参数从句*](..\chapter3\05_Declarations.html#parameter_clause) [*函数结果*](..\chapter3\05_Declarations.html#function_result) _可选_ **in**
|
||||
> *闭包签名(Signational)* → [*标识符集*](..\chapter3\02_Lexical_Structure.html#identifier_list) [*函数结果*](..\chapter3\05_Declarations.html#function_result) _可选_ **in**
|
||||
> *闭包签名(Signational)* → [*捕获(Capature)集*](..\chapter3\04_Expressions.html#capture_list) [*参数从句*](..\chapter3\05_Declarations.html#parameter_clause) [*函数结果*](..\chapter3\05_Declarations.html#function_result) _可选_ **in**
|
||||
> *闭包签名(Signational)* → [*捕获(Capature)集*](..\chapter3\04_Expressions.html#capture_list) [*标识符集*](..\chapter3\02_Lexical_Structure.html#identifier_list) [*函数结果*](..\chapter3\05_Declarations.html#function_result) _可选_ **in**
|
||||
> *闭包签名(Signational)* → [*捕获(Capature)集*](..\chapter3\04_Expressions.html#capture_list) **in**
|
||||
> *捕获(Capature)集* → **[** [*捕获(Capature)说明符*](..\chapter3\04_Expressions.html#capture_specifier) [*表达式*](..\chapter3\04_Expressions.html#expression) **]**
|
||||
> *捕获(Capature)说明符* → **weak** | **unowned** | **unowned(safe)** | **unowned(unsafe)**
|
||||
|
||||
<!-- -->
|
||||
@ -518,8 +644,8 @@ _________________
|
||||
<!-- -->
|
||||
|
||||
> 圆括号表达式(Parenthesized Expression)语法
|
||||
> *圆括号表达式* → **(** [*表达式元素列表*](..\chapter3\04_Expressions.html#expression_element_list) _可选_ **)**
|
||||
> *表达式元素列表* → [*表达式元素*](..\chapter3\04_Expressions.html#expression_element) | [*表达式元素*](..\chapter3\04_Expressions.html#expression_element) **,** [*表达式元素列表*](..\chapter3\04_Expressions.html#expression_element_list)
|
||||
> *圆括号表达式* → **(** [*表达式元素集*](..\chapter3\04_Expressions.html#expression_element_list) _可选_ **)**
|
||||
> *表达式元素集* → [*表达式元素*](..\chapter3\04_Expressions.html#expression_element) | [*表达式元素*](..\chapter3\04_Expressions.html#expression_element) **,** [*表达式元素集*](..\chapter3\04_Expressions.html#expression_element_list)
|
||||
> *表达式元素* → [*表达式*](..\chapter3\04_Expressions.html#expression) | [*标识符*](..\chapter3\02_Lexical_Structure.html#identifier) **:** [*表达式*](..\chapter3\04_Expressions.html#expression)
|
||||
|
||||
<!-- -->
|
||||
@ -557,7 +683,7 @@ _________________
|
||||
|
||||
> 显式成员表达式语法
|
||||
> *显示成员表达式* → [*后置表达式*](..\chapter3\04_Expressions.html#postfix_expression) **.** [*十进制数字*](..\chapter3\02_Lexical_Structure.html#decimal_digit)
|
||||
> *显示成员表达式* → [*后置表达式*](..\chapter3\04_Expressions.html#postfix_expression) **.** [*标识符*](..\chapter3\02_Lexical_Structure.html#identifier) [*泛型参数子句*](GenericParametersAndArguments.html#generic_argument_clause) _可选_
|
||||
> *显示成员表达式* → [*后置表达式*](..\chapter3\04_Expressions.html#postfix_expression) **.** [*标识符*](..\chapter3\02_Lexical_Structure.html#identifier) [*泛型参数从句*](GenericParametersAndArguments.html#generic_argument_clause) _可选_
|
||||
|
||||
<!-- -->
|
||||
|
||||
@ -572,7 +698,7 @@ _________________
|
||||
<!-- -->
|
||||
|
||||
> 附属脚本表达式语法
|
||||
> *附属脚本表达式* → [*后置表达式*](..\chapter3\04_Expressions.html#postfix_expression) **[** [*表达式列表*](..\chapter3\04_Expressions.html#expression_list) **]**
|
||||
> *附属脚本表达式* → [*后置表达式*](..\chapter3\04_Expressions.html#postfix_expression) **[** [*表达式集*](..\chapter3\04_Expressions.html#expression_list) **]**
|
||||
|
||||
<!-- -->
|
||||
|
||||
@ -588,11 +714,14 @@ _________________
|
||||
## 词法结构
|
||||
|
||||
> 标识符语法
|
||||
> *标识符* → [*标识符头(Head)*](..\chapter3\02_Lexical_Structure.html#identifier_head) [*标识符字符列表*](..\chapter3\02_Lexical_Structure.html#identifier_characters) _可选_
|
||||
> *标识符* → **`** [*标识符头(Head)*](..\chapter3\02_Lexical_Structure.html#identifier_head) [*标识符字符列表*](..\chapter3\02_Lexical_Structure.html#identifier_characters) _可选_ **`**
|
||||
> *标识符* → [*标识符头(Head)*](..\chapter3\02_Lexical_Structure.html#identifier_head) [*标识符字符集*](..\chapter3\02_Lexical_Structure.html#identifier_characters) _可选_
|
||||
> *标识符* → [*标识符头(Head)*](..\chapter3\02_Lexical_Structure.html#identifier_head) [*标识符字符集*](..\chapter3\02_Lexical_Structure.html#identifier_characters) _可选_
|
||||
> *标识符* → [*隐式参数名*](..\chapter3\02_Lexical_Structure.html#implicit_parameter_name)
|
||||
> *标识符列表* → [*标识符*](..\chapter3\02_Lexical_Structure.html#identifier) | [*标识符*](..\chapter3\02_Lexical_Structure.html#identifier) **,** [*标识符列表*](..\chapter3\02_Lexical_Structure.html#identifier_list)
|
||||
> *标识符集* → [*标识符*](..\chapter3\02_Lexical_Structure.html#identifier) | [*标识符*](..\chapter3\02_Lexical_Structure.html#identifier) **,** [*标识符集*](..\chapter3\02_Lexical_Structure.html#identifier_list)
|
||||
> *标识符头(Head)* → Upper- or lowercase letter A through Z
|
||||
|
||||
> *标识符头(Head)* → _
|
||||
|
||||
> *标识符头(Head)* → U+00A8, U+00AA, U+00AD, U+00AF, U+00B2–U+00B5, or U+00B7–U+00BA
|
||||
> *标识符头(Head)* → U+00BC–U+00BE, U+00C0–U+00D6, U+00D8–U+00F6, or U+00F8–U+00FF
|
||||
> *标识符头(Head)* → U+0100–U+02FF, U+0370–U+167F, U+1681–U+180D, or U+180F–U+1DBF
|
||||
@ -610,13 +739,19 @@ _________________
|
||||
> *标识符字符* → 数值 0 到 9
|
||||
> *标识符字符* → U+0300–U+036F, U+1DC0–U+1DFF, U+20D0–U+20FF, or U+FE20–U+FE2F
|
||||
> *标识符字符* → [*标识符头(Head)*](..\chapter3\02_Lexical_Structure.html#identifier_head)
|
||||
> *标识符字符列表* → [*标识符字符*](..\chapter3\02_Lexical_Structure.html#identifier_character) [*标识符字符列表*](..\chapter3\02_Lexical_Structure.html#identifier_characters) _可选_
|
||||
> *隐式参数名* → **$** [*十进制数字列表*](..\chapter3\02_Lexical_Structure.html#decimal_digits)
|
||||
> *标识符字符集* → [*标识符字符*](..\chapter3\02_Lexical_Structure.html#identifier_character) [*标识符字符集*](..\chapter3\02_Lexical_Structure.html#identifier_characters) _可选_
|
||||
> *隐式参数名* → **$** [*十进制数字集*](..\chapter3\02_Lexical_Structure.html#decimal_digits)
|
||||
|
||||
<!-- -->
|
||||
|
||||
> 字面量语法
|
||||
> *字面量* → [*整型字面量*](..\chapter3\02_Lexical_Structure.html#integer_literal) | [*浮点数字面量*](..\chapter3\02_Lexical_Structure.html#floating_point_literal) | [*字符串字面量*](..\chapter3\02_Lexical_Structure.html#string_literal)
|
||||
> *字面量* → [*数值型字面量*](..\chapter3\02_Lexical_Structure.html#integer_literal) | [*字符串字面量*](..\chapter3\02_Lexical_Structure.html#floating_point_literal) | [*布尔字面量*](..\chapter3\02_Lexical_Structure.html#string_literal) | [*空字面量*](TODO)
|
||||
|
||||
> *数值型字面量* → **-** _可选_ [*整形字面量*](TODO) | **-** _可选_ [*浮点型字面量*](TODO)
|
||||
|
||||
> *布尔字面量* → **true** | **false**
|
||||
|
||||
> *空字面量* → **nil**
|
||||
|
||||
<!-- -->
|
||||
|
||||
@ -625,23 +760,23 @@ _________________
|
||||
> *整型字面量* → [*八进制字面量*](..\chapter3\02_Lexical_Structure.html#octal_literal)
|
||||
> *整型字面量* → [*十进制字面量*](..\chapter3\02_Lexical_Structure.html#decimal_literal)
|
||||
> *整型字面量* → [*十六进制字面量*](..\chapter3\02_Lexical_Structure.html#hexadecimal_literal)
|
||||
> *二进制字面量* → **0b** [*二进制数字*](..\chapter3\02_Lexical_Structure.html#binary_digit) [*二进制字面量字符列表*](..\chapter3\02_Lexical_Structure.html#binary_literal_characters) _可选_
|
||||
> *二进制字面量* → **0b** [*二进制数字*](..\chapter3\02_Lexical_Structure.html#binary_digit) [*二进制字面量字符集*](..\chapter3\02_Lexical_Structure.html#binary_literal_characters) _可选_
|
||||
> *二进制数字* → 数值 0 到 1
|
||||
> *二进制字面量字符* → [*二进制数字*](..\chapter3\02_Lexical_Structure.html#binary_digit) | **_**
|
||||
> *二进制字面量字符列表* → [*二进制字面量字符*](..\chapter3\02_Lexical_Structure.html#binary_literal_character) [*二进制字面量字符列表*](..\chapter3\02_Lexical_Structure.html#binary_literal_characters) _可选_
|
||||
> *八进制字面量* → **0o** [*八进字数字*](..\chapter3\02_Lexical_Structure.html#octal_digit) [*八进制字符列表*](..\chapter3\02_Lexical_Structure.html#octal_literal_characters) _可选_
|
||||
> *二进制字面量字符集* → [*二进制字面量字符*](..\chapter3\02_Lexical_Structure.html#binary_literal_character) [*二进制字面量字符集*](..\chapter3\02_Lexical_Structure.html#binary_literal_characters) _可选_
|
||||
> *八进制字面量* → **0o** [*八进制数字*](..\chapter3\02_Lexical_Structure.html#octal_digit) [*八进制字符集*](..\chapter3\02_Lexical_Structure.html#octal_literal_characters) _可选_
|
||||
> *八进字数字* → 数值 0 到 7
|
||||
> *八进制字符* → [*八进字数字*](..\chapter3\02_Lexical_Structure.html#octal_digit) | **_**
|
||||
> *八进制字符列表* → [*八进制字符*](..\chapter3\02_Lexical_Structure.html#octal_literal_character) [*八进制字符列表*](..\chapter3\02_Lexical_Structure.html#octal_literal_characters) _可选_
|
||||
> *十进制字面量* → [*十进制数字*](..\chapter3\02_Lexical_Structure.html#decimal_digit) [*十进制字符列表*](..\chapter3\02_Lexical_Structure.html#decimal_literal_characters) _可选_
|
||||
> *八进制字符* → [*八进制数字*](..\chapter3\02_Lexical_Structure.html#octal_digit) | **_**
|
||||
> *八进制字符集* → [*八进制字符*](..\chapter3\02_Lexical_Structure.html#octal_literal_character) [*八进制字符集*](..\chapter3\02_Lexical_Structure.html#octal_literal_characters) _可选_
|
||||
> *十进制字面量* → [*十进制数字*](..\chapter3\02_Lexical_Structure.html#decimal_digit) [*十进制字符集*](..\chapter3\02_Lexical_Structure.html#decimal_literal_characters) _可选_
|
||||
> *十进制数字* → 数值 0 到 9
|
||||
> *十进制数字列表* → [*十进制数字*](..\chapter3\02_Lexical_Structure.html#decimal_digit) [*十进制数字列表*](..\chapter3\02_Lexical_Structure.html#decimal_digits) _可选_
|
||||
> *十进制字符* → [*十进制数字*](..\chapter3\02_Lexical_Structure.html#decimal_digit) | **_**
|
||||
> *十进制字符列表* → [*十进制字符*](..\chapter3\02_Lexical_Structure.html#decimal_literal_character) [*十进制字符列表*](..\chapter3\02_Lexical_Structure.html#decimal_literal_characters) _可选_
|
||||
> *十六进制字面量* → **0x** [*十六进制数字*](..\chapter3\02_Lexical_Structure.html#hexadecimal_digit) [*十六进制字面量字符列表*](..\chapter3\02_Lexical_Structure.html#hexadecimal_literal_characters) _可选_
|
||||
> *十进制数字集* → [*十进制数字*](..\chapter3\02_Lexical_Structure.html#decimal_digit) [*十进制数字集*](..\chapter3\02_Lexical_Structure.html#decimal_digits) _可选_
|
||||
> *十进制字面量字符* → [*十进制数字*](..\chapter3\02_Lexical_Structure.html#decimal_digit) | **_**
|
||||
> *十进制字面量字符集* → [*十进制字面量字符*](..\chapter3\02_Lexical_Structure.html#decimal_literal_character) [*十进制字面量字符集*](..\chapter3\02_Lexical_Structure.html#decimal_literal_characters) _可选_
|
||||
> *十六进制字面量* → **0x** [*十六进制数字*](..\chapter3\02_Lexical_Structure.html#hexadecimal_digit) [*十六进制字面量字符集*](..\chapter3\02_Lexical_Structure.html#hexadecimal_literal_characters) _可选_
|
||||
> *十六进制数字* → 数值 0 到 9, a through f, or A through F
|
||||
> *十六进制字符* → [*十六进制数字*](..\chapter3\02_Lexical_Structure.html#hexadecimal_digit) | **_**
|
||||
> *十六进制字面量字符列表* → [*十六进制字符*](..\chapter3\02_Lexical_Structure.html#hexadecimal_literal_character) [*十六进制字面量字符列表*](..\chapter3\02_Lexical_Structure.html#hexadecimal_literal_characters) _可选_
|
||||
> *十六进制字面量字符集* → [*十六进制字符*](..\chapter3\02_Lexical_Structure.html#hexadecimal_literal_character) [*十六进制字面量字符集*](..\chapter3\02_Lexical_Structure.html#hexadecimal_literal_characters) _可选_
|
||||
|
||||
<!-- -->
|
||||
|
||||
@ -650,7 +785,8 @@ _________________
|
||||
> *浮点数字面量* → [*十六进制字面量*](..\chapter3\02_Lexical_Structure.html#hexadecimal_literal) [*十六进制分数*](..\chapter3\02_Lexical_Structure.html#hexadecimal_fraction) _可选_ [*十六进制指数*](..\chapter3\02_Lexical_Structure.html#hexadecimal_exponent)
|
||||
> *十进制分数* → **.** [*十进制字面量*](..\chapter3\02_Lexical_Structure.html#decimal_literal)
|
||||
> *十进制指数* → [*浮点数e*](..\chapter3\02_Lexical_Structure.html#floating_point_e) [*正负号*](..\chapter3\02_Lexical_Structure.html#sign) _可选_ [*十进制字面量*](..\chapter3\02_Lexical_Structure.html#decimal_literal)
|
||||
> *十六进制分数* → **.** [*十六进制字面量*](..\chapter3\02_Lexical_Structure.html#hexadecimal_literal) _可选_
|
||||
> *十六进制分数* → **.** [*十六进制数*](..\chapter3\02_Lexical_Structure.html#hexadecimal_literal)
|
||||
[*十六进制字面量字符集*](TODO)_可选_
|
||||
> *十六进制指数* → [*浮点数p*](..\chapter3\02_Lexical_Structure.html#floating_point_p) [*正负号*](..\chapter3\02_Lexical_Structure.html#sign) _可选_ [*十六进制字面量*](..\chapter3\02_Lexical_Structure.html#hexadecimal_literal)
|
||||
> *浮点数e* → **e** | **E**
|
||||
> *浮点数p* → **p** | **P**
|
||||
@ -658,22 +794,72 @@ _________________
|
||||
|
||||
<!-- -->
|
||||
|
||||
> 字符型字面量语法
|
||||
> 字符串型字面量语法
|
||||
> *字符串字面量* → **"** [*引用文本*](..\chapter3\02_Lexical_Structure.html#quoted_text) **"**
|
||||
> *引用文本* → [*引用文本条目*](..\chapter3\02_Lexical_Structure.html#quoted_text_item) [*引用文本*](..\chapter3\02_Lexical_Structure.html#quoted_text) _可选_
|
||||
> *引用文本条目* → [*转义字符*](..\chapter3\02_Lexical_Structure.html#escaped_character)
|
||||
> *引用文本条目* → **\(** [*表达式*](..\chapter3\04_Expressions.html#expression) **)**
|
||||
> *引用文本条目* → **(** [*表达式*](..\chapter3\04_Expressions.html#expression) **)**
|
||||
> *引用文本条目* → 除了", \, U+000A, or U+000D的所有Unicode的字符
|
||||
> *转义字符* → **\0** | **\\** | **\t** | **\n** | **\r** | **\"** | **\'**
|
||||
> *转义字符* → **\x** [*十六进制数字*](..\chapter3\02_Lexical_Structure.html#hexadecimal_digit) [*十六进制数字*](..\chapter3\02_Lexical_Structure.html#hexadecimal_digit)
|
||||
> *转义字符* → **\u** [*十六进制数字*](..\chapter3\02_Lexical_Structure.html#hexadecimal_digit) [*十六进制数字*](..\chapter3\02_Lexical_Structure.html#hexadecimal_digit) [*十六进制数字*](..\chapter3\02_Lexical_Structure.html#hexadecimal_digit) [*十六进制数字*](..\chapter3\02_Lexical_Structure.html#hexadecimal_digit)
|
||||
> *转义字符* → **\U** [*十六进制数字*](..\chapter3\02_Lexical_Structure.html#hexadecimal_digit) [*十六进制数字*](..\chapter3\02_Lexical_Structure.html#hexadecimal_digit) [*十六进制数字*](..\chapter3\02_Lexical_Structure.html#hexadecimal_digit) [*十六进制数字*](..\chapter3\02_Lexical_Structure.html#hexadecimal_digit) [*十六进制数字*](..\chapter3\02_Lexical_Structure.html#hexadecimal_digit) [*十六进制数字*](..\chapter3\02_Lexical_Structure.html#hexadecimal_digit) [*十六进制数字*](..\chapter3\02_Lexical_Structure.html#hexadecimal_digit) [*十六进制数字*](..\chapter3\02_Lexical_Structure.html#hexadecimal_digit)
|
||||
> *转义字符* → **\u** **{** [*十六进制标量数字集*](TODO) **}**
|
||||
> *unicode标量数字集* → Between one and eight hexadecimal digits
|
||||
|
||||
<!-- -->
|
||||
|
||||
> 运算符语法语法
|
||||
> *运算符* → [*运算符字符*](..\chapter3\02_Lexical_Structure.html#operator_character) [*运算符*](..\chapter3\02_Lexical_Structure.html#operator) _可选_
|
||||
> *运算符字符* → **/** | **=** | **-** | **+** | **!** | ***** | **%** | **<** | **>** | **&** | **|** | **^** | **~** | **.**
|
||||
> *运算符* → [*运算符头*](..\chapter3\02_Lexical_Structure.html#operator_character) [*运算符字符集*](..\chapter3\02_Lexical_Structure.html#operator) _可选_
|
||||
> *运算符* → [*点运算符头*](TODO) [*点运算符字符集*](TODO) _可选_
|
||||
> *运算符字符* → **/** | **=** | **-** | **+** | **!** | ***** | **%** | **<** | **>** | **&** | **|** | **^** | **~** | **?**
|
||||
> *运算符头* → U+00A1–U+00A7
|
||||
|
||||
> *运算符头* → U+00A9 or U+00AB
|
||||
|
||||
> *运算符头* → U+00AC or U+00AE
|
||||
|
||||
> *运算符头* → U+00B0–U+00B1, U+00B6, U+00BB, U+00BF, U+00D7, or U+00F7
|
||||
|
||||
> *运算符头* → U+2016–U+2017 or 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
|
||||
|
||||
> *运算符字符* → [*运算符头*](TODO)
|
||||
|
||||
> *运算符字符* → U+0300–U+036F
|
||||
|
||||
> *运算符字符* → U+1DC0–U+1DFF
|
||||
|
||||
> *运算符字符* → U+20D0–U+20FF
|
||||
|
||||
> *运算符字符* → U+FE00–U+FE0F
|
||||
|
||||
> *运算符字符* → U+FE20–U+FE2F
|
||||
|
||||
> *运算符字符* → U+E0100–U+E01EF
|
||||
|
||||
> *运算符字符集* → [*运算符字符*](TODO) [*运算符字符集*](TODO)_可选_
|
||||
|
||||
> *点运算符头* → **..**
|
||||
|
||||
> *点运算符字符* → **.** | [*运算符字符*](TODO)
|
||||
|
||||
> *点运算符字符集* → [*点运算符字符*](TODO) [*点运算符字符集*](TODO) _可选_
|
||||
|
||||
> *二元运算符* → [*运算符*](..\chapter3\02_Lexical_Structure.html#operator)
|
||||
> *前置运算符* → [*运算符*](..\chapter3\02_Lexical_Structure.html#operator)
|
||||
> *后置运算符* → [*运算符*](..\chapter3\02_Lexical_Structure.html#operator)
|
||||
@ -682,37 +868,42 @@ _________________
|
||||
## 类型
|
||||
|
||||
> 类型语法
|
||||
> *类型* → [*数组类型*](..\chapter3\03_Types.html#array_type) | [*函数类型*](..\chapter3\03_Types.html#function_type) | [*类型标识*](..\chapter3\03_Types.html#type_identifier) | [*元组类型*](..\chapter3\03_Types.html#tuple_type) | [*可选类型*](..\chapter3\03_Types.html#optional_type) | [*隐式解析可选类型*](..\chapter3\03_Types.html#implicitly_unwrapped_optional_type) | [*协议合成类型*](..\chapter3\03_Types.html#protocol_composition_type) | [*元型类型*](..\chapter3\03_Types.html#metatype_type)
|
||||
> *类型* → [*数组类型*](..\chapter3\03_Types.html#array_type) | [*字典类型*](TODO) | [*函数类型*](..\chapter3\03_Types.html#function_type) | [*类型标识符*](..\chapter3\03_Types.html#type_identifier) | [*元组类型*](..\chapter3\03_Types.html#tuple_type) | [*可选类型*](..\chapter3\03_Types.html#optional_type) | [*隐式解析可选类型*](..\chapter3\03_Types.html#implicitly_unwrapped_optional_type) | [*协议合成类型*](..\chapter3\03_Types.html#protocol_composition_type) | [*元型类型*](..\chapter3\03_Types.html#metatype_type)
|
||||
|
||||
<!-- -->
|
||||
|
||||
> 类型注解语法
|
||||
> *类型注解* → **:** [*特性(Attributes)列表*](..\chapter3\06_Attributes.html#attributes) _可选_ [*类型*](..\chapter3\03_Types.html#type)
|
||||
> *类型注解* → **:** [*属性(Attributes)集*](..\chapter3\06_Attributes.html#attributes) _可选_ [*类型*](..\chapter3\03_Types.html#type)
|
||||
|
||||
<!-- -->
|
||||
|
||||
> 类型标识语法
|
||||
> *类型标识* → [*类型名称*](..\chapter3\03_Types.html#type_name) [*泛型参数子句*](GenericParametersAndArguments.html#generic_argument_clause) _可选_ | [*类型名称*](..\chapter3\03_Types.html#type_name) [*泛型参数子句*](GenericParametersAndArguments.html#generic_argument_clause) _可选_ **.** [*类型标识*](..\chapter3\03_Types.html#type_identifier)
|
||||
> *类名* → [*标识符*](..\chapter3\02_Lexical_Structure.html#identifier)
|
||||
> *类型标识* → [*类型名称*](..\chapter3\03_Types.html#type_name) [*泛型参数从句*](GenericParametersAndArguments.html#generic_argument_clause) _可选_ | [*类型名称*](..\chapter3\03_Types.html#type_name) [*泛型参数从句*](GenericParametersAndArguments.html#generic_argument_clause) _可选_ **.** [*类型标识符*](..\chapter3\03_Types.html#type_identifier)
|
||||
> *类型名* → [*标识符*](..\chapter3\02_Lexical_Structure.html#identifier)
|
||||
|
||||
<!-- -->
|
||||
|
||||
> 元组类型语法
|
||||
> *元组类型* → **(** [*元组类型主体*](..\chapter3\03_Types.html#tuple_type_body) _可选_ **)**
|
||||
> *元组类型主体* → [*元组类型的元素列表*](..\chapter3\03_Types.html#tuple_type_element_list) **...** _可选_
|
||||
> *元组类型的元素列表* → [*元组类型的元素*](..\chapter3\03_Types.html#tuple_type_element) | [*元组类型的元素*](..\chapter3\03_Types.html#tuple_type_element) **,** [*元组类型的元素列表*](..\chapter3\03_Types.html#tuple_type_element_list)
|
||||
> *元组类型的元素* → [*特性(Attributes)列表*](..\chapter3\06_Attributes.html#attributes) _可选_ **inout** _可选_ [*类型*](..\chapter3\03_Types.html#type) | **inout** _可选_ [*元素名*](..\chapter3\03_Types.html#element_name) [*类型注解*](..\chapter3\03_Types.html#type_annotation)
|
||||
> *元组类型主体* → [*元组类型的元素集*](..\chapter3\03_Types.html#tuple_type_element_list) **...** _可选_
|
||||
> *元组类型的元素集* → [*元组类型的元素*](..\chapter3\03_Types.html#tuple_type_element) | [*元组类型的元素*](..\chapter3\03_Types.html#tuple_type_element) **,** [*元组类型的元素集*](..\chapter3\03_Types.html#tuple_type_element_list)
|
||||
> *元组类型的元素* → [*属性(Attributes)集*](..\chapter3\06_Attributes.html#attributes) _可选_ **inout** _可选_ [*类型*](..\chapter3\03_Types.html#type) | **inout** _可选_ [*元素名*](..\chapter3\03_Types.html#element_name) [*类型注解*](..\chapter3\03_Types.html#type_annotation)
|
||||
> *元素名* → [*标识符*](..\chapter3\02_Lexical_Structure.html#identifier)
|
||||
|
||||
<!-- -->
|
||||
|
||||
> 函数类型语法
|
||||
> *函数类型* → [*类型*](..\chapter3\03_Types.html#type) **->** [*类型*](..\chapter3\03_Types.html#type)
|
||||
> *函数类型* → [*类型*](..\chapter3\03_Types.html#type) **throws** _可选_ **->** [*类型*](..\chapter3\03_Types.html#type)
|
||||
> *函数类型* → [*类型*](TODO) **rethrows** **->** [*类型*](TODO)
|
||||
|
||||
<!-- -->
|
||||
|
||||
> 数组类型语法
|
||||
> *数组类型* → [*类型*](..\chapter3\03_Types.html#type) **[** **]** | [*数组类型*](..\chapter3\03_Types.html#array_type) **[** **]**
|
||||
> *数组类型* → **[** [*类型*](..\chapter3\03_Types.html#array_type) **]**
|
||||
|
||||
<!-- -->
|
||||
> 字典类型语法
|
||||
> *字典类型* → **[** [*类型 **:** 类型*](TODO) **]**
|
||||
|
||||
<!-- -->
|
||||
|
||||
@ -727,9 +918,9 @@ _________________
|
||||
<!-- -->
|
||||
|
||||
> 协议合成类型语法
|
||||
> *协议合成类型* → **protocol** **<** [*协议标识符列表*](..\chapter3\03_Types.html#protocol_identifier_list) _可选_ **>**
|
||||
> *协议标识符列表* → [*协议标识符*](..\chapter3\03_Types.html#protocol_identifier) | [*协议标识符*](..\chapter3\03_Types.html#protocol_identifier) **,** [*协议标识符列表*](..\chapter3\03_Types.html#protocol_identifier_list)
|
||||
> *协议标识符* → [*类型标识*](..\chapter3\03_Types.html#type_identifier)
|
||||
> *协议合成类型* → **protocol** **<** [*协议标识符集*](..\chapter3\03_Types.html#protocol_identifier_list) _可选_ **>**
|
||||
> *协议标识符集* → [*协议标识符*](..\chapter3\03_Types.html#protocol_identifier) | [*协议标识符*](..\chapter3\03_Types.html#protocol_identifier) **,** [*协议标识符集*](..\chapter3\03_Types.html#protocol_identifier_list)
|
||||
> *协议标识符* → [*类型标识符*](..\chapter3\03_Types.html#type_identifier)
|
||||
|
||||
<!-- -->
|
||||
|
||||
@ -738,6 +929,14 @@ _________________
|
||||
|
||||
<!-- -->
|
||||
|
||||
> 类型继承子句语法
|
||||
> *类型继承子句* → **:** [*类型继承列表*](..\chapter3\03_Types.html#type_inheritance_list)
|
||||
> *类型继承列表* → [*类型标识*](..\chapter3\03_Types.html#type_identifier) | [*类型标识*](..\chapter3\03_Types.html#type_identifier) **,** [*类型继承列表*](..\chapter3\03_Types.html#type_inheritance_list)
|
||||
> 类型继承从句语法
|
||||
|
||||
> *类型继承从句* → **:** [*类条件(class-requirement))*](TODO) **,** [*类型继承集*](..\chapter3\03_Types.html#type_inheritance_list)
|
||||
|
||||
> *类型继承从句* → **:** [*类条件(class-requirement))*](TODO)
|
||||
|
||||
> *类型继承从句* → **:** [*类型继承集*](TODO)
|
||||
|
||||
> *类型继承集* → [*类型标识符*](..\chapter3\03_Types.html#type_identifier) | [*类型标识符*](..\chapter3\03_Types.html#type_identifier) **,** [*类型继承集*](..\chapter3\03_Types.html#type_inheritance_list)
|
||||
|
||||
> *类条件* → **class**
|
||||
|
||||
Reference in New Issue
Block a user