「这是我参与11月更文挑战的第6天,活动详情查看:2021最后一次更文挑战」。
什么是运算符
运算符是一种特殊符号,可与一个或多个值一起使用以产生某种效果。例如,加法运算符 (+) 将两个数字相加并得出这两个数字的总和,如 let a = b + c。
你可以将把运算符看做是具有唯一名称的函数,该函数可以在不同的位置调用,例如值的前面、中间和后面,而在值的前面又叫前缀运算符、在值的中面又叫中缀运算符、在值的后面又叫后缀运算符。
Swift 系统自带的运算符
这里整理俩个常见的运算符(算术运算符 和 比较运算符),更多的运算符请看文档。
算术运算符
Operator | Description | Example |
---|---|---|
+ | 俩值相加 | A + B |
− | 左侧的值减去右侧的值 | A − B |
* | 将两值相乘 | A * B |
/ | 分子除以分母的值 | B / A |
% | 分子除以分母的余数 | B % A |
比较运算符
Operator | Description | Example |
---|---|---|
== | 检查两值是否相等;如果是,则条件变为真。 | A == B |
!= | 检查两个值是否相等;如果值不相等,则条件为真。 | A != B |
检查左侧的值是否大于右侧的值;如果是,则条件变为真。 | A > B | |
< | 检查左侧的值是否小于右侧的值;如果是,则条件变为真。 | A < B |
>= | 检查左侧的值是否大于或等于右侧的值;如果是,则条件变为真。 | A >= B |
<= | 检查左侧的值是否小于或等于右侧的值;如果是,则条件变为真。 | A <= B |
运算符重载
我们可以对Class和Struct可以提供它们自己对现有运算符的实现。并非每种类型的运算符都可以重载。比如:
- 您不能重载和创建自定义三元运算符。
- 您不能重载默认赋值运算符 (=)。
下面让我们重载一些运算符吧:
重载通用运算符
extension String {
static func * (lhs: String, rhs: Int) -> String { // <1>
return String(repeating: lhs, count: rhs) // <2>
}
}
重载前缀运算符:
extension String {
static prefix func -(str: String) -> String {
return String(str.reversed())
}
}
重载后缀运算符:
extension String {
static postfix func ...(str: String) -> String { // <1>
return str + "..."
}
}
自定义运算符
如果现有的运算符对你来说不够用,Swift 允许你定义一个新的运算符。
自定义复合赋值运算符
struct Teacher {
let name: String
private(set) var stus: [Student]
mutating func add(_ stu: Student) {
stus.append(stu)
}
}
struct Student {
let name: String
}
extension Teacher {
static func += (lhs: inout Teacher, rhs: Student) {
lhs.stus.add(rhs)
}
}
我们需要做的第一件事就是告诉 Swift 我们的新操作符
自定义中缀运算符
infix operator +-: AdditionPrecedence
这是声明新中缀运算符的语法。
infix operator +-: AdditionPrecedence
extension Set {
static func +- (lhs: Set, rhs: Set) -> Set {
return lhs.union(rhs)
}
}
但是我们需要注意的是中缀运算符有点复杂,需要设置优先级组。如果在一个语句中有多个运算符,Swift 需要该组才能知道应该首先执行哪个运算符。您可以在 Apple 的运算符声明页面上找到所有可用的运算符及其优先级组。
运算符优先级表 完整的请看官方文档
Operators | Examples |
---|---|
BitwiseShiftPrecedence | >> << |
MultiplicationPrecedence | % * / |
AdditionPrecedence | - + - ^ | |
RangeFormationPrecedence | ..< ... |
CastingPrecedence | is ,as , as? , 和 as! |
NilCoalescingPrecedence | ?? |
ComparisonPrecedence | != > < >= <= === == |
LogicalConjunctionPrecedence | && .& |
LogicalDisjunctionPrecedence | .| .|| .^ |
TernaryPrecedence | ? : |
AssignmentPrecedence | |= %= /= *= >>= <<= ^= += -= |
自定义后缀运算符
如何声明其实跟中缀运算符并没有太大不同。我们需要做的唯一区别是将关键字从 更改infix
为postfix
。
postfix operator ++
postfix func ++(lhs: inout Int) -> Int {
let temp = lhs
lhs += 1
return temp
}
postfix operator --
postfix func --(lhs: inout Int) -> Int {
let temp = lhs
lhs -= 1
return temp
}
自定义前缀运算符
跟上面同理,我们需要做的唯一区别是将关键字从 更改infix
为prefix
。
prefix operator ++
prefix func ++(lhs: inout Int) -> Int {
lhs += 1
return lhs
}
prefix operator --
prefix func --(lhs: inout Int) -> Int {
lhs -= 1
return lhs
}
上面我们重新写了swift 取消的 ++ -- 的运算符,至于swift 为啥取消这个运算符,可以查看官方的解释。
重载现有运算符和自定义运算符的区别
如您所见,重载现有运算符和自定义运算符之间的唯一区别是声明了一个新运算符。如果你没有这样做,编译器会给你这个错误。
static func *** (lhs: String, rhs: Int) -> String {
return String(repeating: lhs, count: rhs)
}
//error: Operator implementation without matching operator declaration。
扩展--泛型运算符
结束
自定义运算符和运算符重载是一个非常强大的功能,可以让我们在不需要嵌套函数调用的情况下减少冗长,这可能会给我们提供更清晰的代码。然而,它也可能会导致我们获得难以阅读的代码,这对其他开发人员来说变得非常令人生畏和困惑。