/*
操作符方法與操作符的定制
到目前為止,我們已經(jīng)學(xué)習(xí)了swift的絕大部分的語法特性持搜。本節(jié)中,我們還要學(xué)習(xí)swift的另一個靈活
多樣的語法特性 —— 操作符方法。我們可以為自己定義的類或者結(jié)構(gòu)體類型構(gòu)建出一套已有的基本算數(shù)邏輯
操作符(加減乘除)宏娄,而且我們還能自己創(chuàng)建出swift語法系統(tǒng)沒有的獨特操作符(比如 +++, =>等等)。
操作符簡介:
1.前綴操作符: -x逮壁, !x, ~x
2.中綴操作符: a + b, a - b , a * b
3.后綴操作符: x... , a.count(成員訪問操作符), a[0](下標(biāo))
*/
// 1. 對已有操作符的重載
/*
我們?yōu)樽约憾x的結(jié)構(gòu)體和類類型的對象提供了對已有操作符方法的重載孵坚。比如,我們定義一個復(fù)數(shù)類型窥淆,然后
用基本的加減乘除等符號對兩個復(fù)數(shù)類型的對象進行操作卖宠。
*/
print("\n---------1. 對已有操作符的重載-----------\n")
struct ComplexNumber {
/// 表示實數(shù)的存儲式實例屬性
var real: Double
/// 表示虛數(shù)的存儲式實例屬性
var imag: Double
/// 對正數(shù)前綴操作符進行重載
static prefix func + (num: ComplexNumber) -> ComplexNumber {
return num
}
/// 對取相反數(shù)的前綴操作符進行重載
static prefix func - (num: ComplexNumber) -> ComplexNumber {
return ComplexNumber(real: -num.real, imag: -num.imag)
}
/// 對 ~ 前綴操作符進行重載
static prefix func ~ (num: ComplexNumber) -> ComplexNumber {
return ComplexNumber(real: num.real, imag: -num.imag)
}
/// 對加法中綴操作符進行重載
static func + (a:ComplexNumber, b: ComplexNumber) -> ComplexNumber {
return ComplexNumber(real: a.real + b.real, imag: a.imag + b.imag)
}
/// 對減法中綴操作符進行重載
static func - (a: ComplexNumber, b: ComplexNumber) -> ComplexNumber {
return ComplexNumber(real: a.real - b.real, imag: a.imag - b.imag)
}
/// 對乘法中綴操作符進行重載
static func * (a: ComplexNumber, b: ComplexNumber) -> ComplexNumber {
return ComplexNumber(real: a.real * b.real, imag: a.imag * b.imag)
}
/// 對除法中綴操作符進行重載
static func / (a: ComplexNumber, b: ComplexNumber) -> ComplexNumber {
return ComplexNumber(real: a.real / b.real, imag: a.imag / b.imag)
}
/// 對 ++ 后綴操作符進行重載
/// 這里將它作為復(fù)數(shù)的取模運算
/// 從swift3.0之后, ++ 已經(jīng)不能作為遞增運算符來使用了
static postfix func ++ (num: ComplexNumber) -> Double {
return sqrt(num.real * num.real + num.imag * num.imag)
}
/// 對 += 進行重載哦
static func += (a: inout ComplexNumber, b: ComplexNumber) -> Void {
a.real += b.real
a.imag += b.imag
}
/// 對 -= 進行重載
static func -= (a: inout ComplexNumber, b: ComplexNumber) -> Void {
a.real -= b.real
a.imag -= b.imag
}
}
// 使用
var a = ComplexNumber(real: 3.0, imag: 4.0)
var b = ComplexNumber(real: -1.0, imag: 2.0)
// 對兩個復(fù)數(shù)相加
var c = a + b
print("a + b = \(c)")
print("a - b = \(a - b)")
print("a * b = \(a * b)")
print("a / b = \(a / b)")
c = -a
print("-a = \(c)")
c = ~a
print("~a = \(c)")
/*
注意:
當(dāng)我們要重載一個前綴操作符的時候忧饭,就需要添加prefix關(guān)鍵字進行顯式聲明扛伍;
當(dāng)我們要重載一個后綴操作符的時候,就需要添加postfix關(guān)鍵字進行顯示指明词裤。
當(dāng)我們要重載一個中綴操作符的時候刺洒,不需要添加任何關(guān)鍵字鳖宾。
*/
// 2. 可定制的操作符
/*
當(dāng)我們定制在swift語法系統(tǒng)中不存在的操作符,比如逆航, +++鼎文, =>等,我們可以定制的操作符可包含swift
中大部分的標(biāo)點符號因俐,而以下標(biāo)點符號不允許出現(xiàn)在定制的操作符中:
( 拇惋、) 、[ 抹剩、] 蚤假、{ 、} 吧兔、" 磷仰、' 、; 境蔼、: 灶平、@ 、\ 箍土、` 逢享、, 、# 吴藻、_ 和 $
如果我們要在定制操作符中包含 . 符號瞒爬,那么它必須出現(xiàn)在一開始,然后后面可進行任意添加沟堡。所以像 .+ 侧但、.. 、.+. 都是合法的可定制的操作符;而像 +. 、+.- 都是非法的抵恋。
定制操作符可以用以下符號作為首字符:/ 、= 榨汤、- 、+ 、! 、* 趾娃、% 、< 缔御、> 抬闷、& 、| 刹淌、^ 饶氏、? 及 ~。但是有勾,當(dāng)我們要定制后綴操作符時疹启,就不能以 ? 和 ! 作為首字符了。
Swift規(guī)定了以下操作符作為編譯器保留的操作符蔼卡,不可進行定制和重載:= 喊崖、-> 、// 雇逞、/* 荤懂、*/ 、. 塘砸。< 节仿、& 、? 這些不可作為前綴操作符進行定制或重載掉蔬。? 不可作為中綴操作符被重載廊宪。> 、! 女轿、? 這些不可作為后綴操作符被定制或重載箭启。
在Swift編程語言中,我們使用操作符的過程中還得注意:前綴操作符與后綴操作符跟其操作數(shù)之間應(yīng)該緊貼蛉迹,兩者之間不應(yīng)該存在任何空白符傅寡,否則該操作符可能被Swift編譯器判定為中綴操作符,從而引起編譯錯誤北救。而在使用中綴操作符時荐操,操作符與左操作數(shù)和右操作數(shù)之間都分別應(yīng)該用一個空白符隔開,這樣既美觀珍策,而且也能減輕編譯器的詞法淀零、語法解析壓力。
*/
// 3.定制前綴操作符
/*
本節(jié)中我們一起學(xué)習(xí)如何定制前綴操作符膛壹。
*/
print("\n---------3.定制前綴操作符----------\n")
/// 聲明新的操作符 &^
prefix operator &^
/// 實現(xiàn) &^
prefix func &^ (op: Int) -> Int {
return op & (op * op)
}
/// 定義結(jié)構(gòu)體MyData類型
struct MyData {
// 存儲屬性
var data: Int
static prefix func &^ (op: MyData) -> MyData {
return MyData(data: op.data & (op.data * op.data))
}
}
let x = 3
let y = &^x
print("y = \(y)")
let m = MyData(data: 5)
let n = &^m
print("n = \(n.data)")
let f = &^(m.data + 1)
print("c = \(f)")
// 4. 定制后綴操作符
/*
定制后綴操作符的過程與前綴操作符差不多驾中,不過在聲明定制后綴操作符的時候使用關(guān)鍵字postfix operator.
*/
print("\n--------4. 定制后綴操作符-----------\n")
/// 定義一個新的定制操作符
postfix operator |<
postfix func |< (op: Int) -> Int {
return op < 0 ? -op : op * 2
}
let me = -1|<
print("me = \(me)")
// 結(jié)果是:me = -2
/*
為什么呢?
因為負(fù)數(shù)操作符的優(yōu)先級低于后綴操作符模聋,所以先執(zhí)行后綴操作符肩民,結(jié)果是 2, 再與負(fù)數(shù)操作符結(jié)合链方,就變成了 -2 .
*/
let you = 3|< + (-1)|<
print("you = \(you)")
// 注意: 一般前綴操作符的優(yōu)先級要低于后綴操作符
// 5. 定制中綴操作符
/*
定制中綴操作符要復(fù)雜一些持痰,因為中綴操作符種類豐富,在表達式中也往往用得最多祟蚀。
定制中綴操作符方法:
infix operator 關(guān)鍵字 : 優(yōu)先級組
*/
print("\n--------5. 定制中綴操作符----------\n")
/// 聲明一個 *+ 中綴操作符
infix operator *+ : MultiplicationPrecedence
/// 實現(xiàn)這個中綴操作符
func *+ <T: SignedInteger>(a: T, b: T) -> T {
return (a * a) + (b * b)
}
/// 實現(xiàn)這個中綴操作符
func *+ <T: FloatingPoint>(a: T, b: T) -> T {
return (a * a) + (b * b)
}
// 使用
let hh = 3 *+ 4
print("hh = \(hh)")
let gg = 3.0 *+ 5.0
print("gg = \(gg)")
/*
我們要想深度定制中綴操作符工窍,還可以通過 precedencegroup 關(guān)鍵字來定義自己的優(yōu)先級組割卖。
優(yōu)先級組有四個屬性:
- higherThan: 表示所定義的優(yōu)先級組的優(yōu)先級所指定已有的優(yōu)先級組。
- lowerThan: 表示所定義的優(yōu)先級組的優(yōu)先級低于所指定的已有的優(yōu)先級組患雏。
- associativity: 表示所定義的優(yōu)先級組的結(jié)合性鹏溯,只能取3種值,left表示左結(jié)合淹仑,right表示右結(jié)合丙挽,
none表示無結(jié)合。 - assignment: 表示是否數(shù)據(jù)賦值型的操作符(比如 +=, -=)等匀借。true表示當(dāng)前定義的優(yōu)先級組所關(guān)聯(lián)的操作符
均為賦值型操作符颜阐;false則表示非賦值型操作符。
*/
precedencegroup MyPre {
/// 其優(yōu)先級比AdditionPrecedence優(yōu)先級高
higherThan: AdditionPrecedence
/// 優(yōu)先級比MultiplicationPrecedence優(yōu)先級低
lowerThan: MultiplicationPrecedence
/// 屬于右結(jié)合
associativity: right
/// 表示非賦值型操作符
assignment: false
}
/// 定義一個中綴操作符
infix operator |-& : MyPre
func |-& <T: BinaryInteger>(a: T, b: T) -> T {
return (a | b) - (a & b)
}
let jj = -1 + 3 |-& 2 * 0
print("jj = \(jj)")
// 6.對操作符方法的引用
/*
既然操作符方法其本質(zhì)是一個函數(shù)吓肋,或是一個方法凳怨,那么我們自然就能對它進行引用了。
*/
print("\n--------6.對操作符方法的引用----------\n")
// 先引用一個已有的操作符: <
// 注意這里的圓括號不能省略是鬼。
let lessref: (Int, Int) -> Bool = (<)
let result = lessref(20, 30)
print("is less? \(result)")
func lessRefTest(op: (Double, Double) -> Bool) {
let result = op(30.1, 20.6)
print("is less: \(result)")
}
lessRefTest(op: <)
/*
注意:
我們自己在寫代碼的時候盡量用文字說明函數(shù)的具體用途猿棉,而不要搞一些莫名其妙的符號,如果怪異的符號太多屑咳,
然后再把他們作為實參一傳萨赁,閱讀代碼的人很容易暈頭轉(zhuǎn)向。
*/