Swift文档Chapter 26 高级运算符


除了基本运算符,Swift还提供了一些高级运算符。

位运算符

Swift支持C语言中的全部位运算符。

  • 按位取反:~
  • 按位与:&
  • 按位或:|
  • 按位异或:^

按位左移、右移运算符

按位左移运算符(<<) 和 按位右移运算符(>>)可以对一个数的所有位进行指定位数的左移和右移。
对一个数进行按位左移或按位右移,相当于对这个数进行乘以2或除以2的运算。将一个整数左移一位,等价于将这个数乘以2,同样地,将一个整数右移一位,等价于将这个数除以2。

无符号整数进行移位的规则如下(逻辑移位):

  1. 已存在的位按指定的位数进行左移和右移。
  2. 任何因移动而超出整型存储范围的位都会被丢弃。
  3. 用 0 来填充移位后产生的空白位。

有符号整数的移位是对二进制补码进行移位,当对有符号整数进行按位右移运算时,遵循与无符号整数相同的规则,但是对于移位产生的空白位使用符号位进行填充,而不是用0。这个行为可以确保有符号整数的符号位不会因为右移运算而改变,这通常被称为算术移位。

溢出运算符

Swift提供三个运算符,当发生溢出时不会报错,而是会直接截断。分别是溢出加法(&+),溢出减法(&-),溢出乘法(&*)。

运算符函数

类和结构体可以为现有的运算符提供自定义的实现。这通常被称为运算符重载
下面的例子展示了如何让自定义的结构体支持加法运算符(+)。算术加法运算符是一个二元运算符,因为它是对两个值进行运算,同时它还可以称为中缀运算符,因为它出现在两个值中间。

struct Vector2D {
    var x = 0.0, y = 0.0
}

extension Vector2D {
    static func + (left: Vector2D, right: Vector2D) -> Vector2D {
        return Vector2D(x: left.x + right.x, y: left.y + right.y)
    }
}

前缀和后缀运算符

上个例子演示了一个二元中缀运算符的自定义实现。类与结构体也能提供标准一元运算符的实现。一元运算符只运算一个值。当运算符出现在值之前时,它就是前缀的(例如 -a),而当它出现在值之后时,它就是后缀的(例如 b!)。
要实现前缀或者后缀运算符,需要在声明运算符函数的时候在func关键字之前指定prefix或者postfix修饰符。

复合赋值运算符?

复合赋值运算符将赋值运算符(=)与其它运算符进行结合。例如,将加法与赋值结合成加法赋值运算符(+=)。在实现的时候,需要把运算符的左参数设置成 inout 类型,因为这个参数的值会在运算符函数内直接被修改。

extension Vector2D {
    static func += (left: inout Vector2D, right: Vector2D) {
        left = left + right
    }
}

等价运算符

通常情况下,自定义的类和结构体没有对等价运算符进行默认实现,等价运算符通常被称为相等运算符(==)与不等运算符(!=)。
为了使用等价运算符对自定义的类型进行判等运算,需要为“相等”运算符提供自定义实现,实现的方法与其它中缀运算符一样, 并且增加对标准库Equatable协议的遵循。
多数简单情况下,您可以使用 Swift 为您提供的等价运算符默认实现。Swift 为以下数种自定义类型提供等价运算符的默认实现:

  • 只拥有存储属性,并且它们全都遵循 Equatable 协议的结构体;
  • 只拥有关联类型,并且它们全都遵循 Equatable 协议的枚举;
  • 没有关联类型的枚举。

自定义运算符

新的运算符要使用 operator 关键字在全局作用域内进行定义,同时还要指定 prefix、infix 或者 postfix 修饰符。

自定义中缀运算符的优先级

每个自定义中缀运算符都属于某个优先级组。优先级组指定了这个运算符相对于其他中缀运算符的优先级和结合性。而没有明确放入某个优先级组的自定义中缀运算符将会被放到一个默认的优先级组内,其优先级高于三元运算符。