前缀和后缀运算符
类与结构体也能提供标准一元运算符的实现。一元运算符只运算一个值。当运算符出现在值之前时,它就是前缀的(例如 -a
),而当它出现在值之后时,它就是后缀的(例如 b!
)。
要实现前缀或者后缀运算符,需要在声明运算符函数的时候在 func
关键字之前指定 prefix
或者 postfix
修饰符:
extension Vector2D {
static prefix func - (vector: Vector2D) -> Vector2D {
return Vector2D(x: -vector.x, y: -vector.y)
}
}
这段代码为 Vector2D
类型实现了一元运算符(-a
)。由于该运算符是前缀运算符,所以这个函数需要加上 prefix
修饰符。
对于简单数值,一元负号运算符可以对它们的正负性进行改变。对于 Vector2D
来说,该运算将其 x
和 y
属性的正负性都进行了改变:
let positive = Vector2D(x: 3.0, y: 4.0)
let negative = -positive
// negative 是一个值为 (-3.0, -4.0) 的 Vector2D 实例
let alsoPositive = -negative
// alsoPositive 是一个值为 (3.0, 4.0) 的 Vector2D 实例
复合赋值运算符
复合赋值运算符将赋值运算符(=
)与其它运算符进行结合。例如,将加法与赋值结合成加法赋值运算符(+=
)。在实现的时候,需要把运算符的左参数设置成 inout
类型,因为这个参数的值会在运算符函数内直接被修改。
在下面的例子中,对 Vector2D
实例实现了一个加法赋值运算符函数:
extension Vector2D {
static func += (left: inout Vector2D, right: Vector2D) {
left = left + right
}
}
因为加法运算在之前已经定义过了,所以在这里无需重新定义。在这里可以直接利用现有的加法运算符函数,用它来对左值和右值进行相加,并再次赋值给左值:
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)
不能对默认的赋值运算符(
=
)进行重载。只有复合赋值运算符可以被重载。同样地,也无法对三元条件运算符 (a ? b : c
) 进行重载。
等价运算符
通常情况下,自定义的类和结构体没有对等价运算符进行默认实现,等价运算符通常被称为相等运算符(==
)与不等运算符(!=
)。
为了使用等价运算符对自定义的类型进行判等运算,需要为“相等”运算符提供自定义实现,实现的方法与其它中缀运算符一样, 并且增加对标准库 Equatable
协议的遵循:
extension Vector2D: Equatable {
static func == (left: Vector2D, right: Vector2D) -> Bool {
return (left.x == right.x) && (left.y == right.y)
}
}
上述代码实现了“相等”运算符(==
)来判断两个 Vector2D
实例是否相等。对于 Vector2D
来说,“相等”意味着“两个实例的 x
和 y
都相等”,这也是代码中用来进行判等的逻辑。如果你已经实现了“相等”运算符,通常情况下你并不需要自己再去实现“不等”运算符(!=
)。标准库对于“不等”运算符提供了默认的实现,它简单地将“相等”运算符的结果进行取反后返回。
现在我们可以使用这两个运算符来判断两个 Vector2D
实例是否相等:
let twoThree = Vector2D(x: 2.0, y: 3.0)
let anotherTwoThree = Vector2D(x: 2.0, y: 3.0)
if twoThree == anotherTwoThree {
print("These two vectors are equivalent.")
}
// 打印“These two vectors are equivalent.”
多数简单情况下,您可以使用 Swift 为您提供的等价运算符默认实现。Swift 为以下数种自定义类型提供等价运算符的默认实现:
- 只拥有存储属性,并且它们全都遵循
Equatable
协议的结构体 - 只拥有关联类型,并且它们全都遵循
Equatable
协议的枚举 - 没有关联类型的枚举
在类型原始的声明中声明遵循 Equatable
来接收这些默认实现。
下面为三维位置向量 (x, y, z)
定义的 Vector3D
结构体,与 Vector2D
类似。由于 x
,y
和 z
属性都是 Equatable
类型,Vector3D
获得了默认的等价运算符实现。
struct Vector3D: Equatable {
var x = 0.0, y = 0.0, z = 0.0
}
let twoThreeFour = Vector3D(x: 2.0, y: 3.0, z: 4.0)
let anotherTwoThreeFour = Vector3D(x: 2.0, y: 3.0, z: 4.0)
if twoThreeFour == anotherTwoThreeFour {
print("These two vectors are also equivalent.")
}
// 打印“These two vectors are also equivalent.”
评论列表(0条)