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