在一些编程语言中, **
可以让右操作数作为左操作数的指数来进行幂运算,但是在 Swift 中却没有。下面我们来新增一个自定义的 **
操作符。
通常
^
被用作上标,但是它已经被用来执行一个按位异或
运算了。
自定义运算符
要把 **
作为运算符添加到 Swift 中,首先要定义一个运算符:
infix operator ** : BitwiseShiftPrecedence
- infix 指定了它是一个二元操作符,有左右两个操作数参数
- operator 是一个保留字,其必须写在
prefix
,infix
或者postfix
之后 **
是运算符本身- BitwiseShiftPrecedence:指定运算符的优先级(precedencegroup)为
位移优先级
infix operator ** : BitwiseShiftPrecedence
func ** (left: Double, right: Double) -> Double {
pow(left, right)
}
2 ** 3
// 8
precedencegroup 优先级
一个操作符需要属于某个特定的优先级。precedencegroup 定义了一个操作符的优先级。Swift 标准库中内置了几种常用的操作符的优先级,加法优先级 (AdditionPrecedence) 、乘法优先级 (MultiplicationPrecedence)和位移优先级(BitwiseShiftPrecedence),更多的优先级可以查看 Swift 文档。
下面是三个运算符优先级的定义:
precedencegroup AdditionPrecedence {
associativity: left
higherThan: RangeFormationPrecedence
}
precedencegroup MultiplicationPrecedence {
associativity: left
higherThan: AdditionPrecedence
}
precedencegroup BitwiseShiftPrecedence {
higherThan: MultiplicationPrecedence
}
可以看出操作符优先级的定义和类型声明有些相似。如果内置的优先级不满足我们的要求,我们还可以自定义运算符的优先级。
// 自定义操作符的运算优先级
precedencegroup CustomerPrecedence {
// 结合律
associativity: none
// 优先级设置
// 高于加法和减法(AdditionPrecedence)
higherThan: AdditionPrecedence
// 低于乘法和除法(MultiplicationPrecedence)
lowerThan: MultiplicationPrecedence
}
associativity
定义了结合律,即当多个同类的操作符顺序出现的计算顺序。比如常见的加减法都是 left,就是说多个加减法同时出现时按照从左往右的顺序计算 (因为加法满足交换律,所以这个顺序无所谓,但是减法的话计算顺序就很重要了)。不允许连续出现的操作符,可以写成 none。
higherThan
和 lowerThan
用于指定自定义的优先级高于和低于另一个优先级。
**如果合适的话,当创建了一个自定义的运算符时,还要创建相应的赋值操作符,就像 +
和 +=
一样。 **
infix operator **= : BitwiseShiftPrecedence
func **= (left: inout Double, right: Double) {
left = left ** right
}
注意:这里的 left 是
inout
的,因为该赋值操作符改变了原来的值。
SwiftyColor 中的运算符
SwiftyColor 是一个通过数值快速生成颜色的库。其中自定义了 ~
操作符来快速的给 Color 设置 alpha 值,自定义了 %
来表示一个百分数。
#if os(iOS)
import UIKit
public typealias Color = UIColor
#elseif os(OSX)
import AppKit
public typealias Color = NSColor
#endif
extension Int {
public var color: Color {
let red = CGFloat(self as Int >> 16 & 0xff) / 255
let green = CGFloat(self >> 8 & 0xff) / 255
let blue = CGFloat(self & 0xff) / 255
return Color(red: red, green: green, blue: blue, alpha: 1)
}
}
precedencegroup AlphaPrecedence {
associativity: left
higherThan: RangeFormationPrecedence
lowerThan: AdditionPrecedence
}
infix operator ~ : AlphaPrecedence
public func ~ (color: Color, alpha: Int) -> Color {
return color ~ CGFloat(alpha)
}
public func ~ (color: Color, alpha: Float) -> Color {
return color ~ CGFloat(alpha)
}
public func ~ (color: Color, alpha: CGFloat) -> Color {
return color.withAlphaComponent(alpha)
}
/// e.g. `50%`
postfix operator %
public postfix func % (percent: Int) -> CGFloat {
return CGFloat(percent)%
}
public postfix func % (percent: Float) -> CGFloat {
return CGFloat(percent)%
}
public postfix func % (percent: CGFloat) -> CGFloat {
return percent / 100
}