1、概述
除了一些基本的操作符,Swift提供了几种能够执行更加复杂值操纵的高级操作符。其中包括你所熟悉的C和OC中的按位位移操作符。
与C语言的算数运算符不同,Swift中的算数操作符默认不会溢出(overflow)。溢出行为被捕获并且作为一个错误被报告。如果要参与溢出行为,使用Swift的默认会溢出的第二套算数操作符,例如溢出加(&+)。Swift中的会溢出的操作符都以&开头。
Swift允许为你自定义的类型提供自己的标准操作符实现。
Swift允许自由的定义你自己的自定义的中缀,前缀,后缀,赋值操作符,以及自定义的优先级和结合律。并且你可以扩展已存在的类型来支持你定义的自定义操作符。
2、位操作符
位操作符允许操纵数据结构中的独立的原始数据位。常用于低级别的程序,例如图形程序和设备驱动创建。当你工作于来自外部源的原始数据,例如通过自定义协议交流的数据的编解码,位操作符也是很有用的。
1)位NOT操作符(~),翻转一个数字中的所有位。前缀操作符,直接在值的前面,没有空格
例:let initialBits: UInt8 = 0b00001111
let invertedBits = ~initialBits //等于11110000
2)位AND操作符。从两个被操作数返回一个新的值,只有两个被操作数对应位都为1,返回值的对应位才为1.
例: let firstSixBits: UInt8 = 0b11111100
let lastSixBits: UInt8 = 0b00111111
let middleFourBits = firstSixBits & lastSixBits //等于0b00111100
3)位OR操作符。从两个被操作数返回一个新的值,只要两个被操作数对应位任意一个为1,返回值的对应位就为1.
例:let someBits: UInt8 = 0b10110010
let moreBits: UInt8 = 0b01011110
let combinedbits = someBits | moreBits //等于0b11111110
4)位XOR操作符。异或操作符(^)。操作符返回一个新的值,返回值的每一位是:被操作的两个数对应位不相同返回1,相同返回0
例:let firstBits: UInt8 = 0b00010100
let otherBits: UInt8 = 0b00000101
let outputBits = firstBits ^ otherBits //等于0b00010001
5)按位左移和右移操作符。逻辑位移(logic shift)。按位左移(<<)有乘以2的效果,按位右移(>>)有除以2的效果。
无符号整数的移位行为:
(1)存在的位被左移或者右移相应的位数
(2)移动之后超出整数存储范围的位抛弃
(3)原始位左移右移之后空出的位置0
例:let shiftBits: UInt8 = 4 // 00000100 in binary
shiftBits << 1 // 00001000
shiftBits << 2 // 00010000
shiftBits << 5 // 10000000
shiftBits << 6 // 00000000
shiftBits >> 2 // 00000001
有符号整数的位移行为:有符号整数使用第一位标明整数是正(0)的还是负(1)的。剩余的为存储实际的值。
正整数存储于无符号整数相同,除了最高位为0,代表是正值:
负整数存储有一些不同。它们存储的是2的n次方减去它的绝对值,其中n代表值的位数。一个8位数有7位值位:
这种负数编码方式叫做二进制补码(two's complement)。这种表示方法有几个好处:
(1)加法运算。如-1+-4。只需要执行标准的8位二进制加法即可,抛弃任何超出的部分
(2)负数的位移操作和正数位移得以统一。有一个规则:当你右移有符号整数,规则与无符号整数一样,只是填充空余位为标志位而不是0。这样保证了右移之后符号位相同,被称为算术位移(arithmetic shift)
2、溢出操作符
如果你试图给一个不能保留这个值的整形常量或变量插入一个值,默认情况下,Swift报一个错误,而不是允许一个无效的值被创建。这个行为保证了安全性。超出范围的赋值会引起错误:
var potentialOverflow = Int16.max
// potentialOverflow等于32767, Int16的最大值
potentialOverflow+=1
// Error
当你特别的需要溢出条件来阶段可用位的数字,Swift提供三种算术溢出操作符,允许整数计算的溢出行为。这些操作符都以&开头:
Overflow addtion (&+)
Overflow subtraction (&-)
Overflow multiplication (&*)
1)值溢出。数字可以在正数和负数两个方向都溢出。例:
var unsignedOverflow = UInt8.max
// unsignedOverflow 等于255, UInt8的最大值
unsignedOverflow=unsignedOverflow&+1
// unsignedOverflow现在等于0
var unsignedOverflow = UInt8.min
// unsignedOverflow等于0, UInt8最小值
unsignedOverflow = unsignedOverflow&-1
// unsignedOverflow等于255
有符号整数的溢出计算,符号位也作为加减数字的一部分来计算。例:
var signedOverflow=Int8.min
// signedOverflow等于-128, Int8的最小值
signedOverflow=signedOverflow&-1
// signedOverflow等于127
对于有符号和无符号整数,正方向的溢出计算回环从最大有效值到最小有效值。负方向的溢出计算回环从最小有效值到最大有效值。
3、优先级和结合律
操作符优先级使得一些操作符比其他操作符有更高的优先级,优先级高的先实施。操作符结合律定义了同一优先级的操作符怎么来组合。操作符优先级解释了以下表达式等于17:
2 + 3 % 4 * 5
高优先级的操作符比低优先级的先计算。而同一级别优先级操作符哪个先计算由结合律来确定,等同于隐式的添加了括号:
2 + ((3 % 4)* 5)
4、操作符方法(operator methods)
类和结构体可以提供已存在操作符的自己的实现,这成为操作符重载(overloading the existing operators)。下面的例子实现了结构体内算法加操作符,二元中缀操作符(binary infix operator):
struct Vector2D{
var x=0.0,y=0.0
}
extension Vector2D{
static func + (left:Vector2D,right:Vector2D) ->Vector2D{
returnVector2D(x:left.x+right.x,y:left.y+right.y)
}
}
let vector = Vector2D(x:3.0,y:1.0)
let anotherVector = Vector2D(x:2.0,y:4.0)
let combinedVector = vector+anotherVector
// combinedVector is a Vector2D instance with values of (5.0, 5.0)
前缀和后缀操作符。通过在func关键字前面写prefix和postfix来实现前缀或者后缀一元操作符:
extension Vector2D{
static prefix func - (vector:Vector2D) ->Vector2D{
returnVector2D(x: -vector.x,y: -vector.y)
}
}
let positive=Vector2D(x:3.0,y:4.0)
let negative= -positive
// negative is a Vector2D instance with values of (-3.0, -4.0)
let alsoPositive= -negative
// alsoPositive is a Vector2D instance with values of (3.0, 4.0)
混合的赋值操作符(compound assignment operators)。其方法重载需标记左输入参数类型为inout。例:
extension Vector2D{
static func += (left:inoutVector2D,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 now has values of (4.0, 6.0)
赋值操作符和三元条件操作符不能被重载(overload)
相等操作符(equivalence operators)。为自定义类型实现相等操作符实现与其他中缀操作符一样。例:
extension Vector2D{
static func == (left:Vector2D,right:Vector2D) ->Bool{
return(left.x==right.x) && (left.y==right.y)
}
static func != (left:Vector2D,right:Vector2D) ->Bool{
return!(left==right)
}
}
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.")
}
// Prints "These two vectors are equivalent."
5、自定义操作符
新的操作符声明在一个全局级别,使用operator关键字,并且以prefix、infix、postfix做修饰符。例:
extension Vector2D{
static prefix func +++ (vector:inoutVector2D) ->Vector2D{
vector+=vector
return vector
}
}
var toBeDoubled = Vector2D(x:1.0,y:4.0)
let afterDoubling = +++toBeDoubled
// toBeDoubled now has values of (2.0, 8.0)
// afterDoubling also has values of (2.0, 8.0)
注意与运算符重载的区别
自定义中缀运算符的优先级。一个自定义的中缀运算符如果没有显示的放进一个优先级组,那么它会被富裕一个默认的优先级组,高于三元条件运算符的优先级。下面的例子定义了一个新的自定义中缀运算符+-。从属于运算符组AdditionPrecedence:
infix operator +- : AdditionPrecedence
extension Vector2D{
static func +- (left:Vector2D,right:Vector2D) ->Vector2D{
returnVector2D(x:left.x+right.x,y:left.y-right.y)
}
}
let firstVector = Vector2D(x:1.0,y:2.0)
let secondVector = Vector2D(x:3.0,y:4.0)
let plusMinusVector = firstVector +- secondVector
// plusMinusVector is a Vector2D instance with values of (4.0, -2.0)
AdditionPrecedence的具体细节参考Swift语言参考Operators章节
不需要对前缀或者后缀操作符指定优先级,如果对一个操作数同时应用了前缀以及后缀运算符,后缀运算符首先起作用。