swift4.1 系統(tǒng)學(xué)習(xí)二十四 操作符方法與操作符的定制

/*
操作符方法與操作符的定制

到目前為止,我們已經(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)先級組有四個屬性:

  1. higherThan: 表示所定義的優(yōu)先級組的優(yōu)先級所指定已有的優(yōu)先級組。
  2. lowerThan: 表示所定義的優(yōu)先級組的優(yōu)先級低于所指定的已有的優(yōu)先級組患雏。
  3. associativity: 表示所定義的優(yōu)先級組的結(jié)合性鹏溯,只能取3種值,left表示左結(jié)合淹仑,right表示右結(jié)合丙挽,
    none表示無結(jié)合。
  4. 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)向。
*/

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末兆龙,一起剝皮案震驚了整個濱河市杖爽,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌紫皇,老刑警劉巖慰安,帶你破解...
    沈念sama閱讀 218,036評論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異聪铺,居然都是意外死亡化焕,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,046評論 3 395
  • 文/潘曉璐 我一進店門铃剔,熙熙樓的掌柜王于貴愁眉苦臉地迎上來撒桨,“玉大人,你說我怎么就攤上這事键兜》锢啵” “怎么了?”我有些...
    開封第一講書人閱讀 164,411評論 0 354
  • 文/不壞的土叔 我叫張陵普气,是天一觀的道長谜疤。 經(jīng)常有香客問我,道長,這世上最難降的妖魔是什么夷磕? 我笑而不...
    開封第一講書人閱讀 58,622評論 1 293
  • 正文 為了忘掉前任履肃,我火速辦了婚禮,結(jié)果婚禮上坐桩,老公的妹妹穿的比我還像新娘尺棋。我一直安慰自己,他們只是感情好撕攒,可當(dāng)我...
    茶點故事閱讀 67,661評論 6 392
  • 文/花漫 我一把揭開白布陡鹃。 她就那樣靜靜地躺著烘浦,像睡著了一般抖坪。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上闷叉,一...
    開封第一講書人閱讀 51,521評論 1 304
  • 那天擦俐,我揣著相機與錄音,去河邊找鬼握侧。 笑死蚯瞧,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的品擎。 我是一名探鬼主播埋合,決...
    沈念sama閱讀 40,288評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼萄传!你這毒婦竟也來了甚颂?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,200評論 0 276
  • 序言:老撾萬榮一對情侶失蹤秀菱,失蹤者是張志新(化名)和其女友劉穎振诬,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體衍菱,經(jīng)...
    沈念sama閱讀 45,644評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡赶么,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,837評論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了脊串。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片辫呻。...
    茶點故事閱讀 39,953評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖琼锋,靈堂內(nèi)的尸體忽然破棺而出印屁,到底是詐尸還是另有隱情,我是刑警寧澤斩例,帶...
    沈念sama閱讀 35,673評論 5 346
  • 正文 年R本政府宣布雄人,位于F島的核電站,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏础钠。R本人自食惡果不足惜恰力,卻給世界環(huán)境...
    茶點故事閱讀 41,281評論 3 329
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望旗吁。 院中可真熱鬧踩萎,春花似錦、人聲如沸很钓。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,889評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽码倦。三九已至企孩,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間袁稽,已是汗流浹背勿璃。 一陣腳步聲響...
    開封第一講書人閱讀 33,011評論 1 269
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留推汽,地道東北人补疑。 一個月前我還...
    沈念sama閱讀 48,119評論 3 370
  • 正文 我出身青樓,卻偏偏與公主長得像歹撒,于是被迫代替她去往敵國和親莲组。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,901評論 2 355

推薦閱讀更多精彩內(nèi)容