Merge pull request #903 from wuqiuhao/feature/advanced_operators

Swift5.0 AdvancedOperators 章节更新
This commit is contained in:
Jie Liang
2019-03-27 08:11:36 -05:00
committed by GitHub
2 changed files with 32 additions and 30 deletions

View File

@ -202,3 +202,4 @@ let optionalNumber: Int? = 3
things.append(optionalNumber) // 警告 things.append(optionalNumber) // 警告
things.append(optionalNumber as Any) // 没有警告 things.append(optionalNumber as Any) // 没有警告
``` ```

View File

@ -22,7 +22,7 @@ Swift 支持 C 语言中的全部位运算符,接下来会一一介绍。
按位取反运算符是一个前缀运算符,直接放在运算数之前,并且它们之间不能添加任何空格: 按位取反运算符是一个前缀运算符,直接放在运算数之前,并且它们之间不能添加任何空格:
```swift ```Swift
let initialBits: UInt8 = 0b00001111 let initialBits: UInt8 = 0b00001111
let invertedBits = ~initialBits // 等于 0b11110000 let invertedBits = ~initialBits // 等于 0b11110000
``` ```
@ -39,7 +39,7 @@ let invertedBits = ~initialBits // 等于 0b11110000
在下面的示例当中,`firstSixBits``lastSixBits` 中间 4 个位的值都为 `1`。使用按位与运算符之后,得到二进制数值 `00111100`,等价于无符号十进制数的 `60` 在下面的示例当中,`firstSixBits``lastSixBits` 中间 4 个位的值都为 `1`。使用按位与运算符之后,得到二进制数值 `00111100`,等价于无符号十进制数的 `60`
```swift ```Swift
let firstSixBits: UInt8 = 0b11111100 let firstSixBits: UInt8 = 0b11111100
let lastSixBits: UInt8 = 0b00111111 let lastSixBits: UInt8 = 0b00111111
let middleFourBits = firstSixBits & lastSixBits // 等于 00111100 let middleFourBits = firstSixBits & lastSixBits // 等于 00111100
@ -47,13 +47,13 @@ let middleFourBits = firstSixBits & lastSixBits // 等于 00111100
### Bitwise OR Operator按位或运算符 {#bitwise_or_operator} ### Bitwise OR Operator按位或运算符 {#bitwise_or_operator}
*按位或运算符(`|`* 可以对两个数的比特位进行比较。它返回一个新的数,只要两个数的对应位中有*任意一个*为 `1` 时,新数的对应位就为 `1` *按位或运算符(`|`*可以对两个数的比特位进行比较。它返回一个新的数,只要两个数的对应位中有*任意一个*为 `1` 时,新数的对应位就为 `1`
![Art/bitwiseOR_2x.png](https://docs.swift.org/swift-book/_images/bitwiseOR_2x.png) ![Art/bitwiseOR_2x.png](https://docs.swift.org/swift-book/_images/bitwiseOR_2x.png)
在下面的示例中,`someBits``moreBits` 存在不同的位被设置为 `1`。使用按位或运算符之后,得到二进制数值 `11111110`,等价于无符号十进制数的 `254` 在下面的示例中,`someBits``moreBits` 存在不同的位被设置为 `1`。使用按位或运算符之后,得到二进制数值 `11111110`,等价于无符号十进制数的 `254`
```swift ```Swift
let someBits: UInt8 = 0b10110010 let someBits: UInt8 = 0b10110010
let moreBits: UInt8 = 0b01011110 let moreBits: UInt8 = 0b01011110
let combinedbits = someBits | moreBits // 等于 11111110 let combinedbits = someBits | moreBits // 等于 11111110
@ -67,7 +67,7 @@ let combinedbits = someBits | moreBits // 等于 11111110
在下面的示例当中,`firstBits``otherBits` 都有一个自己为 `1`,而对方为 `0` 的位。按位异或运算符将新数的这两个位都设置为 `1`。在其余的位上 `firstBits``otherBits` 是相同的,所以设置为 `0` 在下面的示例当中,`firstBits``otherBits` 都有一个自己为 `1`,而对方为 `0` 的位。按位异或运算符将新数的这两个位都设置为 `1`。在其余的位上 `firstBits``otherBits` 是相同的,所以设置为 `0`
```swift ```Swift
let firstBits: UInt8 = 0b00010100 let firstBits: UInt8 = 0b00010100
let otherBits: UInt8 = 0b00000101 let otherBits: UInt8 = 0b00000101
let outputBits = firstBits ^ otherBits // 等于 00010001 let outputBits = firstBits ^ otherBits // 等于 00010001
@ -95,7 +95,7 @@ let outputBits = firstBits ^ otherBits // 等于 00010001
下面的代码演示了 Swift 中的移位运算: 下面的代码演示了 Swift 中的移位运算:
```swift ```Swift
let shiftBits: UInt8 = 4 // 即二进制的 00000100 let shiftBits: UInt8 = 4 // 即二进制的 00000100
shiftBits << 1 // 00001000 shiftBits << 1 // 00001000
shiftBits << 2 // 00010000 shiftBits << 2 // 00010000
@ -106,7 +106,7 @@ shiftBits >> 2 // 00000001
可以使用移位运算对其他的数据类型进行编码和解码: 可以使用移位运算对其他的数据类型进行编码和解码:
```swift ```Swift
let pink: UInt32 = 0xCC6699 let pink: UInt32 = 0xCC6699
let redComponent = (pink & 0xFF0000) >> 16 // redComponent 是 0xCC即 204 let redComponent = (pink & 0xFF0000) >> 16 // redComponent 是 0xCC即 204
let greenComponent = (pink & 0x00FF00) >> 8 // greenComponent 是 0x66 即 102 let greenComponent = (pink & 0x00FF00) >> 8 // greenComponent 是 0x66 即 102
@ -165,7 +165,7 @@ let blueComponent = pink & 0x0000FF // blueComponent 是 0x99即 153
例如,`Int16` 型整数能容纳的有符号整数范围是 `-32768``32767`。当为一个 `Int16` 类型的变量或常量赋予的值超过这个范围时,系统就会报错: 例如,`Int16` 型整数能容纳的有符号整数范围是 `-32768``32767`。当为一个 `Int16` 类型的变量或常量赋予的值超过这个范围时,系统就会报错:
```swift ```Swift
var potentialOverflow = Int16.max var potentialOverflow = Int16.max
// potentialOverflow 的值是 32767这是 Int16 能容纳的最大整数 // potentialOverflow 的值是 32767这是 Int16 能容纳的最大整数
potentialOverflow += 1 potentialOverflow += 1
@ -186,7 +186,7 @@ potentialOverflow += 1
这个示例演示了当我们对一个无符号整数使用溢出加法(`&+`)进行上溢运算时会发生什么: 这个示例演示了当我们对一个无符号整数使用溢出加法(`&+`)进行上溢运算时会发生什么:
```swift ```Swift
var unsignedOverflow = UInt8.max var unsignedOverflow = UInt8.max
// unsignedOverflow 等于 UInt8 所能容纳的最大整数 255 // unsignedOverflow 等于 UInt8 所能容纳的最大整数 255
unsignedOverflow = unsignedOverflow &+ 1 unsignedOverflow = unsignedOverflow &+ 1
@ -199,7 +199,7 @@ unsignedOverflow = unsignedOverflow &+ 1
当允许对一个无符号整数进行下溢运算时也会产生类似的情况。这里有一个使用溢出减法运算符(`&-`)的例子: 当允许对一个无符号整数进行下溢运算时也会产生类似的情况。这里有一个使用溢出减法运算符(`&-`)的例子:
```swift ```Swift
var unsignedOverflow = UInt8.min var unsignedOverflow = UInt8.min
// unsignedOverflow 等于 UInt8 所能容纳的最小整数 0 // unsignedOverflow 等于 UInt8 所能容纳的最小整数 0
unsignedOverflow = unsignedOverflow &- 1 unsignedOverflow = unsignedOverflow &- 1
@ -212,7 +212,7 @@ unsignedOverflow = unsignedOverflow &- 1
溢出也会发生在有符号整型上。针对有符号整型的所有溢出加法或者减法运算都是按位运算的方式执行的,符号位也需要参与计算,正如[按位左移、右移运算符](#bitwise_left_and_right_shift_operators)所描述的。 溢出也会发生在有符号整型上。针对有符号整型的所有溢出加法或者减法运算都是按位运算的方式执行的,符号位也需要参与计算,正如[按位左移、右移运算符](#bitwise_left_and_right_shift_operators)所描述的。
```swift ```Swift
var signedOverflow = Int8.min var signedOverflow = Int8.min
// signedOverflow 等于 Int8 所能容纳的最小整数 -128 // signedOverflow 等于 Int8 所能容纳的最小整数 -128
signedOverflow = signedOverflow &- 1 signedOverflow = signedOverflow &- 1
@ -233,7 +233,7 @@ signedOverflow = signedOverflow &- 1
当考虑一个复合表达式的计算顺序时,运算符的优先级和结合性是非常重要的。举例来说,运算符优先级解释了为什么下面这个表达式的运算结果会是 `17` 当考虑一个复合表达式的计算顺序时,运算符的优先级和结合性是非常重要的。举例来说,运算符优先级解释了为什么下面这个表达式的运算结果会是 `17`
```swift ```Swift
2 + 3 % 4 * 5 2 + 3 % 4 * 5
// 结果是 17 // 结果是 17
``` ```
@ -248,25 +248,25 @@ signedOverflow = signedOverflow &- 1
而乘法运算与取余运算的优先级*相同*。这时为了得到正确的运算顺序,还需要考虑结合性。乘法运算与取余运算都是左结合的。可以将这考虑成,从它们的左边开始为这两部分表达式都隐式地加上括号: 而乘法运算与取余运算的优先级*相同*。这时为了得到正确的运算顺序,还需要考虑结合性。乘法运算与取余运算都是左结合的。可以将这考虑成,从它们的左边开始为这两部分表达式都隐式地加上括号:
```swift ```Swift
2 + ((3 % 4) * 5) 2 + ((3 % 4) * 5)
``` ```
`(3 % 4)` 等于 `3`,所以表达式相当于: `(3 % 4)` 等于 `3`,所以表达式相当于:
```swift ```Swift
2 + (3 * 5) 2 + (3 * 5)
``` ```
`3 * 5` 等于 `15`,所以表达式相当于: `3 * 5` 等于 `15`,所以表达式相当于:
```swift ```Swift
2 + 15 2 + 15
``` ```
因此计算结果为 `17` 因此计算结果为 `17`
有关 Swift 标准库提供的操作符信息,包括操作符优先级组和结核性设置的完整列表,请参见[操作符声明](https://developer.apple.com/documentation/swift/swift_standard_library/operator_declarations)。 有关 Swift 标准库提供的操作符信息,包括操作符优先级组和结核性设置的完整列表,请参见[操作符声明](https://developer.apple.com/documentation/swift/operator_declarations)。
> 注意 > 注意
> >
@ -280,7 +280,7 @@ signedOverflow = signedOverflow &- 1
例子中定义了一个名为 `Vector2D` 的结构体用来表示二维坐标向量 `(x, y)`,紧接着定义了一个可以将两个 `Vector2D` 结构体实例进行相加的*运算符函数* 例子中定义了一个名为 `Vector2D` 的结构体用来表示二维坐标向量 `(x, y)`,紧接着定义了一个可以将两个 `Vector2D` 结构体实例进行相加的*运算符函数*
```swift ```Swift
struct Vector2D { struct Vector2D {
var x = 0.0, y = 0.0 var x = 0.0, y = 0.0
} }
@ -298,7 +298,7 @@ extension Vector2D {
这个类方法可以在任意两个 `Vector2D` 实例中间作为中缀运算符来使用: 这个类方法可以在任意两个 `Vector2D` 实例中间作为中缀运算符来使用:
```swift ```Swift
let vector = Vector2D(x: 3.0, y: 1.0) let vector = Vector2D(x: 3.0, y: 1.0)
let anotherVector = Vector2D(x: 2.0, y: 4.0) let anotherVector = Vector2D(x: 2.0, y: 4.0)
let combinedVector = vector + anotherVector let combinedVector = vector + anotherVector
@ -315,7 +315,7 @@ let combinedVector = vector + anotherVector
要实现前缀或者后缀运算符,需要在声明运算符函数的时候在 `func` 关键字之前指定 `prefix` 或者 `postfix` 修饰符: 要实现前缀或者后缀运算符,需要在声明运算符函数的时候在 `func` 关键字之前指定 `prefix` 或者 `postfix` 修饰符:
```swift ```Swift
extension Vector2D { extension Vector2D {
static prefix func - (vector: Vector2D) -> Vector2D { static prefix func - (vector: Vector2D) -> Vector2D {
return Vector2D(x: -vector.x, y: -vector.y) return Vector2D(x: -vector.x, y: -vector.y)
@ -327,7 +327,7 @@ extension Vector2D {
对于简单数值,一元负号运算符可以对它们的正负性进行改变。对于 `Vector2D` 来说,该运算将其 `x``y` 属性的正负性都进行了改变: 对于简单数值,一元负号运算符可以对它们的正负性进行改变。对于 `Vector2D` 来说,该运算将其 `x``y` 属性的正负性都进行了改变:
```swift ```Swift
let positive = Vector2D(x: 3.0, y: 4.0) let positive = Vector2D(x: 3.0, y: 4.0)
let negative = -positive let negative = -positive
// negative 是一个值为 (-3.0, -4.0) 的 Vector2D 实例 // negative 是一个值为 (-3.0, -4.0) 的 Vector2D 实例
@ -341,7 +341,7 @@ let alsoPositive = -negative
在下面的例子中,对 `Vector2D` 实例实现了一个加法赋值运算符函数: 在下面的例子中,对 `Vector2D` 实例实现了一个加法赋值运算符函数:
```swift ```Swift
extension Vector2D { extension Vector2D {
static func += (left: inout Vector2D, right: Vector2D) { static func += (left: inout Vector2D, right: Vector2D) {
left = left + right left = left + right
@ -351,7 +351,7 @@ extension Vector2D {
因为加法运算在之前已经定义过了,所以在这里无需重新定义。在这里可以直接利用现有的加法运算符函数,用它来对左值和右值进行相加,并再次赋值给左值: 因为加法运算在之前已经定义过了,所以在这里无需重新定义。在这里可以直接利用现有的加法运算符函数,用它来对左值和右值进行相加,并再次赋值给左值:
```swift ```Swift
var original = Vector2D(x: 1.0, y: 2.0) var original = Vector2D(x: 1.0, y: 2.0)
let vectorToAdd = Vector2D(x: 3.0, y: 4.0) let vectorToAdd = Vector2D(x: 3.0, y: 4.0)
original += vectorToAdd original += vectorToAdd
@ -368,7 +368,7 @@ original += vectorToAdd
为了使用等价运算符对自定义的类型进行判等运算,需要为“相等”运算符提供自定义实现,实现的方法与其它中缀运算符一样, 并且增加对标准库 `Equatable` 协议的遵循: 为了使用等价运算符对自定义的类型进行判等运算,需要为“相等”运算符提供自定义实现,实现的方法与其它中缀运算符一样, 并且增加对标准库 `Equatable` 协议的遵循:
```swift ```Swift
extension Vector2D: Equatable { extension Vector2D: Equatable {
static func == (left: Vector2D, right: Vector2D) -> Bool { static func == (left: Vector2D, right: Vector2D) -> Bool {
return (left.x == right.x) && (left.y == right.y) return (left.x == right.x) && (left.y == right.y)
@ -380,7 +380,7 @@ extension Vector2D: Equatable {
现在我们可以使用这两个运算符来判断两个 `Vector2D` 实例是否相等: 现在我们可以使用这两个运算符来判断两个 `Vector2D` 实例是否相等:
```swift ```Swift
let twoThree = Vector2D(x: 2.0, y: 3.0) let twoThree = Vector2D(x: 2.0, y: 3.0)
let anotherTwoThree = Vector2D(x: 2.0, y: 3.0) let anotherTwoThree = Vector2D(x: 2.0, y: 3.0)
if twoThree == anotherTwoThree { if twoThree == anotherTwoThree {
@ -389,7 +389,7 @@ if twoThree == anotherTwoThree {
// 打印“These two vectors are equivalent.” // 打印“These two vectors are equivalent.”
``` ```
Swift 为以下数种自定义类型提供等价运算符的默认实现: 多数简单情况下,您可以使用 Swift 为您提供的等价运算符默认实现。Swift 为以下数种自定义类型提供等价运算符的默认实现:
- 只拥有存储属性,并且它们全都遵循 `Equatable` 协议的结构体 - 只拥有存储属性,并且它们全都遵循 `Equatable` 协议的结构体
- 只拥有关联类型,并且它们全都遵循 `Equatable` 协议的枚举 - 只拥有关联类型,并且它们全都遵循 `Equatable` 协议的枚举
@ -399,7 +399,7 @@ Swift 为以下数种自定义类型提供等价运算符的默认实现:
下面为三维位置向量 `(x, y, z)` 定义的 `Vector3D` 结构体,与 `Vector2D` 类似。由于 `x``y``z` 属性都是 `Equatable` 类型,`Vector3D` 获得了默认的等价运算符实现。 下面为三维位置向量 `(x, y, z)` 定义的 `Vector3D` 结构体,与 `Vector2D` 类似。由于 `x``y``z` 属性都是 `Equatable` 类型,`Vector3D` 获得了默认的等价运算符实现。
```swift ```Swift
struct Vector3D: Equatable { struct Vector3D: Equatable {
var x = 0.0, y = 0.0, z = 0.0 var x = 0.0, y = 0.0, z = 0.0
} }
@ -418,13 +418,13 @@ if twoThreeFour == anotherTwoThreeFour {
新的运算符要使用 `operator` 关键字在全局作用域内进行定义,同时还要指定 `prefix``infix` 或者 `postfix` 修饰符: 新的运算符要使用 `operator` 关键字在全局作用域内进行定义,同时还要指定 `prefix``infix` 或者 `postfix` 修饰符:
```swift ```Swift
prefix operator +++ prefix operator +++
``` ```
上面的代码定义了一个新的名为 `+++` 的前缀运算符。对于这个运算符,在 Swift 中并没有已知的意义,因此在针对 `Vector2D` 实例的特定上下文中,给予了它自定义的意义。对这个示例来讲,`+++` 被实现为“前缀双自增”运算符。它使用了前面定义的复合加法运算符来让矩阵与自身进行相加,从而让 `Vector2D` 实例的 `x` 属性和 `y` 属性值翻倍。你可以像下面这样通过对 `Vector2D` 添加一个 `+++` 类方法,来实现 `+++` 运算符: 上面的代码定义了一个新的名为 `+++` 的前缀运算符。对于这个运算符,在 Swift 中并没有已知的意义,因此在针对 `Vector2D` 实例的特定上下文中,给予了它自定义的意义。对这个示例来讲,`+++` 被实现为“前缀双自增”运算符。它使用了前面定义的复合加法运算符来让矩阵与自身进行相加,从而让 `Vector2D` 实例的 `x` 属性和 `y` 属性值翻倍。你可以像下面这样通过对 `Vector2D` 添加一个 `+++` 类方法,来实现 `+++` 运算符:
```swift ```Swift
extension Vector2D { extension Vector2D {
static prefix func +++ (vector: inout Vector2D) -> Vector2D { static prefix func +++ (vector: inout Vector2D) -> Vector2D {
vector += vector vector += vector
@ -446,7 +446,7 @@ let afterDoubling = +++toBeDoubled
以下例子定义了一个新的自定义中缀运算符 `+-`,此运算符属于 `AdditionPrecedence` 优先组: 以下例子定义了一个新的自定义中缀运算符 `+-`,此运算符属于 `AdditionPrecedence` 优先组:
```swift ```Swift
infix operator +-: AdditionPrecedence infix operator +-: AdditionPrecedence
extension Vector2D { extension Vector2D {
static func +- (left: Vector2D, right: Vector2D) -> Vector2D { static func +- (left: Vector2D, right: Vector2D) -> Vector2D {
@ -459,8 +459,9 @@ let plusMinusVector = firstVector +- secondVector
// plusMinusVector 是一个 Vector2D 实例,并且它的值为 (4.0, -2.0) // plusMinusVector 是一个 Vector2D 实例,并且它的值为 (4.0, -2.0)
``` ```
这个运算符把两个向量的 `x` 值相加,同时从第一个向量的 `y` 中减去第二个向量的 `y` 。因为它本质上是属于“相加型”运算符,所以将它放置在 `+``-` 等默认中缀“相加型”运算符相同的优先级组中。关于 Swift 标准库提供的运算符,以及完整的运算符优先级组和结合性设置,请参考 [运算符声明](https://developer.apple.com/documentation/swift/swift_standard_library/operator_declarations)。而更多关于优先级组以及自定义操作符和优先级组的语法,请参考[运算符声明](https://docs.swift.org/swift-book/ReferenceManual/Declarations.html#ID380)。 这个运算符把两个向量的 `x` 值相加,同时从第一个向量的 `y` 中减去第二个向量的 `y` 。因为它本质上是属于“相加型”运算符,所以将它放置在 `+``-` 等默认中缀“相加型”运算符相同的优先级组中。关于 Swift 标准库提供的运算符,以及完整的运算符优先级组和结合性设置,请参考 [运算符声明](https://developer.apple.com/documentation/swift/operator_declarations)。而更多关于优先级组以及自定义操作符和优先级组的语法,请参考[运算符声明](./06_Declarations.md#operator_declaration)。
> 注意 > 注意
> >
> 当定义前缀与后缀运算符的时候,我们并没有指定优先级。然而,如果对同一个值同时使用前缀与后缀运算符,则后缀运算符会先参与运算。 > 当定义前缀与后缀运算符的时候,我们并没有指定优先级。然而,如果对同一个值同时使用前缀与后缀运算符,则后缀运算符会先参与运算。