溢出運算符(Overflow Operator)
- Swift的算術(shù)運算符出現(xiàn)溢出時會拋出運行時錯誤
- Swift有溢出運算符(
&+&-&*),用來支持溢出運算
我們先來看一下UInt8和Int8的最大值和最小值
print(Int8.min) // -128
print(Int8.max) // 127
print(UInt8.min) // 0
print(UInt8.max) // 255

其實
溢出運算符就像是一個循環(huán)(蘋果官方給出的圖):
我們先看一下如果不使用溢出運算符,溢出之后會怎樣:

可以看到,如果不使用
溢出運算符,數(shù)據(jù)溢出之后會直接崩潰。下面我們來使用一下
溢出運算符:
var min = UInt8.min
print(min &- 1)
/*輸出結(jié)果*/
255
var max = UInt8.max
print(max &+ 1)
/*輸出結(jié)果*/
0
print(max &* 2) // 等價于 max &+ max
/*輸出結(jié)果*/
254
可以看到,最小值再減一就是最大值,最大值再加一就是最小值,這剛好就是一個循環(huán)。
運算符重載(OPerator Overload)
- 類、結(jié)構(gòu)體、枚舉可以為現(xiàn)有的運算符提供自定義的實現(xiàn),這個操作叫做:運算符重載
下面以結(jié)構(gòu)體為例:
struct Point {
var x: Int, y: Int
}
我們知道直接將兩個結(jié)構(gòu)體相加是不可以的,那么我們?nèi)绾瓮ㄟ^運算符重載來實現(xiàn)兩個結(jié)構(gòu)體相加呢?方法如下:
- 方法一: 直接在外面重載運算符
func +(p1: Point, p2: Point) -> Point {
Point(x: p1.x + p2.x, y: p1.y + p2.y)
}
let p = Point(x: 10, y: 20) + Point(x: 11, y: 22)
print(p)
/*輸出結(jié)果*/
Point(x: 21, y: 42)
- 方法二:在
結(jié)構(gòu)體內(nèi)部重載運算符
在這里要注意,在結(jié)構(gòu)體內(nèi)部重載運算符,必須加上static
image.png
struct Point {
var x: Int, y: Int
static func + (p1: Point, p2: Point) -> Point {
Point(x: p1.x + p2.x, y: p1.y + p2.y)
}
}
一般情況下,建議使用第二種方法來重載運算符
我們再來重載一下其他的運算符:
struct Point {
var x: Int, y: Int
static func + (p1: Point, p2: Point) -> Point {
Point(x: p1.x + p2.x, y: p1.y + p2.y)
}
static func - (p1: Point, p2: Point) -> Point {
Point(x: p1.x - p2.x, y: p1.y - p2.y)
}
static func += (p1: inout Point, p2: Point) {
p1 = p1 + p2
}
// 前綴運算符
static prefix func ++ (p: inout Point) -> Point {
p += Point(x: 1, y: 1)
return p
}
// 后綴運算符
static postfix func ++ (p: inout Point) -> Point {
let tmp = p
p += Point(x: 1, y: 1)
return tmp
}
static func == (p1: Point, p2: Point) -> Bool {
(p1.x == p2.x) && (p1.y == p2.y)
}
}
Equatable
- 要想知道兩個實例是否等價,一般做法是遵守
Equatable協(xié)議,重載==運算符;與此同時,等價于重載了!=運算符
我們來看一下Equatable的定義:
public protocol Equatable {
/// Returns a Boolean value indicating whether two values are equal.
///
/// Equality is the inverse of inequality. For any values `a` and `b`,
/// `a == b` implies that `a != b` is `false`.
///
/// - Parameters:
/// - lhs: A value to compare.
/// - rhs: Another value to compare.
static func == (lhs: Self, rhs: Self) -> Bool
}
下面我們自定義一個類,來遵守以下Equatable協(xié)議
class Person: Equatable {
var age: Int
init(_ age: Int) {
self.age = age
}
static func == (lhs: Person, rhs: Person) -> Bool {
lhs.age == rhs.age
}
}
這里大家可能會有一個疑問,我直接重加==運算符就可以了,為什么還要遵守Equatable協(xié)議呢?
其實,只是單純的重載==運算符,確實是沒什么區(qū)別??墒亲袷?code>Equatable協(xié)議是有一定的含義的:
① 可以明確的高速使用者,當(dāng)前類(或者 結(jié)構(gòu)體 枚舉) 是可以使用==運算符的。
② 我們再上一篇文章Swift進階(十三)泛型中講過,關(guān)聯(lián)類型類型必須遵守Equatable協(xié)議,如果想被關(guān)聯(lián),那就要遵守。
③ 在定義泛型函數(shù),來比較兩個對象是否相等時,泛型要遵守Equatable協(xié)議,否則會報錯,因為泛型可以是任意類型,如果沒有遵守Equatable協(xié)議,那就可能沒有==運算符:

func equal<T: Equatable>(_ a: T, _ b: T) -> Bool {
a == b
}
equal(Person(10), Person(20))
Swift 為以下類型提供默認(rèn)的
Equatable實現(xiàn)
① 沒有關(guān)聯(lián)類型的枚舉
② 只擁有遵守Equatable協(xié)議關(guān)聯(lián)類型的枚舉
③ 只擁有遵守Equatable協(xié)議存儲屬性的結(jié)構(gòu)體引用類型比較存儲的地址值是否相等(是否引用著同一個對象),使用恒等運算符
===、!==,注意此時不用去遵守Equatable協(xié)議`
class Person {
var age: Int
init(_ age: Int) {
self.age = age
}
}
var p1 = Person(10)
var p2 = Person(10)
print(p1 === p2) // false
p2 = p1
print(p1 === p2) // true
Comparable
- 要想比較兩個實例的大小,一般做法是:
□ 遵守Comparable協(xié)議
□ 重載相應(yīng)的運算符
先來看一下Comparable協(xié)議:
public protocol Comparable : Equatable {
/// Returns a Boolean value indicating whether the value of the first
/// argument is less than that of the second argument.
///
/// This function is the only requirement of the `Comparable` protocol. The
/// remainder of the relational operator functions are implemented by the
/// standard library for any type that conforms to `Comparable`.
///
/// - Parameters:
/// - lhs: A value to compare.
/// - rhs: Another value to compare.
static func < (lhs: Self, rhs: Self) -> Bool
/// Returns a Boolean value indicating whether the value of the first
/// argument is less than or equal to that of the second argument.
///
/// - Parameters:
/// - lhs: A value to compare.
/// - rhs: Another value to compare.
static func <= (lhs: Self, rhs: Self) -> Bool
/// Returns a Boolean value indicating whether the value of the first
/// argument is greater than or equal to that of the second argument.
///
/// - Parameters:
/// - lhs: A value to compare.
/// - rhs: Another value to compare.
static func >= (lhs: Self, rhs: Self) -> Bool
/// Returns a Boolean value indicating whether the value of the first
/// argument is greater than that of the second argument.
///
/// - Parameters:
/// - lhs: A value to compare.
/// - rhs: Another value to compare.
static func > (lhs: Self, rhs: Self) -> Bool
}
會發(fā)現(xiàn)Comparable協(xié)議有四個重載運算符,下面我們來實現(xiàn)以下:
// score大的比較大,若score相等,age小的比較大
struct Student: Comparable {
var age: Int
var score: Int
init(_ age: Int, _ score: Int) {
self.age = age
self.score = score
}
static func < (lhs: Student, rhs: Student) -> Bool {
(lhs.score < rhs.score) || (lhs.score == rhs.score && lhs.age > rhs.age)
}
static func > (lhs: Student, rhs: Student) -> Bool {
(lhs.score > rhs.score) || (lhs.score == rhs.score && lhs.age < rhs.age)
}
static func <= (lhs: Student, rhs: Student) -> Bool {
!(lhs > rhs)
}
static func >= (lhs: Student, rhs: Student) -> Bool {
!(lhs < rhs)
}
}
var s1 = Student(age: 10, score: 100)
var s2 = Student(age: 10, score: 120)
var s3 = Student(age: 9, score: 110)
print(s1 > s2) // false
print(s1 >= s2) // false
print(s1 >= s3) // false
print(s1 <= s3) // true
自定義運算符(Custom OPerator)
- 可以自定義新的運算符:在
使用
operator進行聲明
□prefix operator前綴運算符
□postfix operator后綴運算符
□infix operator中綴運算符 : 優(yōu)先級組
precedencegroup 優(yōu)先級組 {
associativity: 結(jié)合性('left'、'right'、'none'),表示運算符運算的方向,或者不允許多個一起使用
higherThan: 比誰的優(yōu)先級高
lowerThan: 比誰的優(yōu)先級底
assignment: true 代表在'可選鏈操作中',擁有和'賦值運算符'一樣的優(yōu)先級
}
precedencegroup MyOperator {
associativity: none
higherThan: AdditionPrecedence
lowerThan: MultiplicationPrecedence
assignment: true
}
prefix operator +++
infix operator +- : MyOperator
struct Point {
var x: Int
var y: Int
static prefix func +++ (point: inout Point) -> Point {
point = Point(x: point.x + point.x, y: point.y + point.y)
return point
}
static func +- (p1: Point, p2: Point) -> Point {
return Point(x: p1.x + p2.x, y: p1.y - p2.y)
}
static func +- (p1: Point?, p2: Point) ->Point {
return Point(x: p1?.x ?? 0 + p2.x, y: p1?.y ?? 0 - p2.y)
}
}
struct Person {
var point: Point
}
var person: Person? = Person(point: Point(x: 10, y: 20))
person?.point +- Point(x: 11, y: 22)
這里解釋一下
優(yōu)先級組里面的assignment是什么意思:
□assignment為true時表示:在'可選鏈操作中',擁有和'賦值運算符'一樣的優(yōu)先級。
什么意思呢?
首先在Swift進階(十)可選鏈中我們講過,如果可選項為nil時,等號后面的函數(shù)(也可以是別的)就不會執(zhí)行。
那么在上面的例子中,person?.point +- Point(x: 11, y: 22)這句代碼表示:如果person為nil,Point(x: 11, y: 22)就不會執(zhí)行,不會去初始化一個Point對象。注意:
□優(yōu)先級組的名字是自己定義的;
□優(yōu)先級組的參數(shù)要嚴(yán)格按照蘋果的文檔來設(shè)置。
蘋果參考文檔:
https://developer.apple.com/documentation/swift/swift_standard_library/operator_declarations
