高级运算符


1.位运算符

1.1按位取反


前置运算符 ~ 对一个操作数的每一位都取反,后紧跟操作数,不加空格


let initialBits: UInt8 = 0b00001111
let invertedBits = ~initialBits  // equals 11110000



1.2按位与


对两个数进行操作,返回一个新的数,两个数的同一位都为1时,输出数才为1


let firstSixBits: UInt8 = 0b11111100
let lastSixBits: UInt8  = 0b00111111
let middleFourBits = firstSixBits & lastSixBits  // equals 00111100



1.3按位或


比较两个数,返回一个新的数,两个数的同一位都不为0时,输出数才为1


let someBits: UInt8 = 0b10110010
let moreBits: UInt8 = 0b01011110
let combinedbits = someBits | moreBits  // equals 11111110



1.4按位异或


比较两个数返回一个新的数,两个数的同一位不同时,输出数才为1,相同输出0


let firstBits: UInt8 = 0b00010100
let otherBits: UInt8 = 0b00000101
let outputBits = firstBits ^ otherBits  // equals 00010001



1.5按位左移/右移


把一个数的比特位按定义的规则向左或向右移动指定的位数,相当于把一个整数乘以或除以一个因子为2的整数,左移相当于乘以2,右移相当于除以2

1.5.1无符号

向左移或向右移动指定的位数,被移出整型存储边界的位数直接抛弃,移动过留下的空白位用零填充,称为逻辑移位


let shiftBits: UInt8 = 4   // 00000100 in binary
shiftBits << 1             // 00001000
shiftBits << 2             // 00010000
shiftBits << 5             // 10000000
shiftBits << 6             // 00000000
shiftBits >> 2             // 00000001

let pink: UInt32 = 0xCC6699
let redComponent = (pink & 0xFF0000) >> 16    // redComponent is 0xCC, or 204
let greenComponent = (pink & 0x00FF00) >> 8   // greenComponent is 0x66, or 102
let blueComponent = pink & 0x0000FF           // blueComponent is 0x99, or 153



1.5.2有符号


有符号整型通过第一个比特位来表达这个数是整数还是负数,0代表正数,1代表负数


有符整型在右移的时候,使用符号位(0/1)填补右移产生的空白,以确保有符号的整型在右移的时候符号不会发生变化



2.溢出运算符


默认Swift不允许往一个整型常量赋予一个它无法承载的大数,这样在操作过大或过小的数时就会很安全


// Int16整型能接受的范围是-32768到32767之间,
var potentialOverflow = Int16.max
// potentialOverflow equals 32767, which is the largest value an Int16 can hold
potentialOverflow += 1
// this causes an error



如果有意在溢出时对有效位进行截断,可采用溢出运算,Swift提供5个&字符开头的溢出运算符



2.1值的上溢出 (&+)



var willOverflow = UInt8.max
// willOverflow equals 255, which is the largest value a UInt8 can hold
willOverflow = willOverflow &+ 1
// willOverflow is now equal to 0



2.2值的下溢出 (&-)



var willUnderflow = UInt8.min
// willUnderflow equals 0, which is the smallest value a UInt8 can hold
willUnderflow = willUnderflow &- 1
// willUnderflow is now equal to 255



2.3除零溢出 (&/)



let x = 1
let y = x / 0

let x = 1
let y = x &/ 0
// y is equal to 0



3.优先级和结合性


运算符的优先级是的一些运算符优先与其他运算符,高优先级的运算符会先计算


2 + 3 * 4 % 5
// this equals 4

2 + ((3 * 4) % 5)



4.运算符函数


让已有的运算符也可以对自定义的类和结构体进行运算,称为运算符重载

在func之前写上属性 @infix 即可定义一个全局的 + 函数


// 参数命名为left 和 right 表示 + 左边和有右边的对象
struct Vector2D {
    var x = 0.0, y = 0.0
}
@infix func + (left: Vector2D, right: Vector2D) -> Vector2D {
    return Vector2D(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)



4.1前置和后置运算符


实现前置后者后置运算符,在定义该运算符的时候与关键字之前标注 @prefix 或 @postfix 属性


@prefix func - (vector: Vector2D) -> Vector2D {
    return Vector2D(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)



4.2组合赋值运算符


组合赋值是其他运算符和赋值运算符一起执行的运算,如 += 把加运算和赋值运算符组合成一个操作,实现一个组合赋值符号需要用 @assignment 属性,还要把运算符的左参数设置成inout, 因为这个参数会在运算符函数内修改这个值


@assignment func += (inout left: 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 now has values of (4.0, 6.0)

// 以下把 @assignment和 @prefix 或 @postfix属性结合起来
@prefix @assignment func ++ (inout vector: Vector2D) -> Vector2D {
    vector += Vector2D(x: 1.0, y: 1.0)
    return vector
}

var toIncrement = Vector2D(x: 3.0, y: 4.0)
let afterIncrement = ++toIncrement
// toIncrement now has values of (4.0, 5.0)
// afterIncrement also has values of (4.0, 5.0)



4.3比较运算符



@infix func == (left: Vector2D, right: Vector2D) -> Bool {
    return (left.x == right.x) && (left.y == right.y)
}
@infix 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 {
    println("These two vectors are equivalent.")
}
// prints "These two vectors are equivalent."



5.自定义运算符


自定义的运算符只能使用以下字符 : / = - + * % < > ! & | ^ 。~

新的运算符声明需要在全局使用operator关键字声明,可以声明为前置,中置或后置


operator prefix +++ {}



定义一个新的前置运算符 +++ 


@prefix @assignment func +++ (inout vector: Vector2D) -> 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)



5.1自定义中置运算符的优先级和结合性


可为自定义的中置运算符指定优先级和结合性,结合性可取值的范围有left,right和none,左结合运算符跟其他优先级相同的左结合写在一起时,会跟左边的操作数结合,同理,右结合运算符会跟右边的操作数结合,非结合运算符不能跟其他相同优先级的运算符写在一起


operator infix +- { associativity left precedence 140 }
func +- (left: Vector2D, right: Vector2D) -> Vector2D {
    return Vector2D(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)