學習Swift程式語言:運算子重載(Operator Overloading)簡介

運算子重載(Operator Overloading)是每個計算機與語言裡面最強大的的功能之一,所以Apple公司也決定在Swift裡面開放它。然而隨著強大力量來臨的同時也意味著更巨大的責任。我們可以輕易地使用它他來實現一個很詭異的運算, 比方說針對數字跟字串進行加減法運算或讓他們相乘除,但是這絕對不是你真的想用來這麼做。


好了,我們說的夠多了,讓我們來看看運算子超載(Operator Overloading)是怎麼一回事吧。

挑戰

這次的教學單的任務非常的容易:擴充乘法運算符的數量為標準功能。你將會用它來進行字串的聯級運算(concatenation operator),但過程卻比想像中的簡單。所以你可以想像我們將完成下面的事情:

在開始埋頭苦幹的撰寫程式碼之前,你可以先停下來想想看你會怎麼來解決這個問題?你會把他分成哪幾個步驟呢?當然,下面是我的做法:

  • 建立結果變數(result variable) 並賦予它初始值- 預設的字串。
  • 建立一個從2開始的迴圈,並且在函式接受到的數字做結束,每個迴圈的執行週期只做一件事情– 把字串加到結果變數上。
  • 將結果顯示到Xcode的console上.

好了,這就是我構思的演算法-我們接著進入到實作的部分吧。

基本的運算子重載(Basic Operator Overloading)

learn-operator-overloading

首先,我們開啟Xcode 並且開啟playground模式。刪除playground模式下所有的內容,並且新增乘法運算函數的原形:

我們剛剛建立的函數有兩個參數 – 左邊參數的型態為String 右邊參數的型態是 Int -最後我們回傳String型態並回傳乘法的執行結果。

有三件事情,你應該在在函式(function)的本體裡面完成。首先,建立結果變數(result variable)並賦予它初始值(initial value)-函式內的String是可變的-你很快就會需要來變動這個值了:

接下來我們執行迴圈,這個迴圈將從2開始執行,一執行到跟函式內接收到的Int數值為止才結束,我們將使用for in的語句來實現流程控制與範圍操作的功能實現:

注意: 我們使用了通配符模式(Wildcard Pattern)來實作這部分的程式。通配符模式匹配並忽略任何值,包含一個底線(_)。當你不關心被匹配的值時,可以使用此模式。更多關參考的資料可以參考 這裡.

只有一件事你應該在Loop循環中執行-更新結果到結果變數(result variable)的字串變數中:

注意: 你也可以把上面的函示改成下面的程式來實作 –我們上面的程式碼會比較簡潔,因為我們採用加法賦值運算符(addition assignment operator)的模式。(譯者註:看來這一章節,原作者想讓大家有更多收穫,教我們很多東西呢,不熟悉加法賦值運算符的同學們可以多多學習喔。):

終於,到了回傳變數的時候到了。

好了,現在我們來使用我們剛剛完成的運算符吧:

好了,就是這樣!這邊只剩下一個問題,我們只能針對字串做乘法運算。那要怎麼實現其他的類型呢?(好比說加法)所以,我們接著使用泛型運算子 (generic operators)來解決這個問題

泛型運算子(Generic Operators)

generic-operators

通用型別 (Generic Types) 預設不被我們的運算函示所支援,所以我們需要一個為她來建立一個協定型別(protocol Type) 。我們在playground下面添加這樣的協定型別(protocol Type):

現在,我們已經為為先的指派運算子(assignment operator)函數加上了協定(protocol):

這個函式擁有左邊跟右邊兩個型態為self的運算元-這是一種很特別的方式來敘述任何型別的資料都可以在協定(protocol)裡面實現。左邊的運算元被標示為inout 寫入讀出(in-out)參數,因為他的值會被修改而且會從函式裡面回傳。

另外,你也可以定義加法運算符函數的原型:

這個函式也擁有左邊跟右邊兩個型態為self的運算元,並且返回相加結果作為作為類型Self的值。在這種情況下,你並不需要使用inout參數了。

下一步,我們來建立String,Int,DoubleFloat等類型的擴充來實現協定型別(protocol Type):

注意:因為你不希望任何東西添加到默認類型擴展的實現都是空的。您只需讓他們為了遵守協議。

現在添加乘法運算符函數的原型到playground檔案中:

這個函數有有兩個參數-左邊的運算元的類型是T右手邊的運算元的類型是Int-並返回乘法結果的值類型為T。您可以使用類型約束,使泛型類型T符合類型協議Type( Type protocol),所以現在明白加法賦值運算了嗎?

注意: 你可以定義類型約束來替代使用關鍵字的方法-雖然我們原先的做法比較簡潔:

該功能的實現是跟我們先前的情況是一模一樣的:

注意: 你可以加法運算來替代上面的功能-請確保在這個case中,它需要被添加在函式的prototype到protocol內,:.

現在我們來看看泛型運算子(generic operators)的運作狀況吧:

好了,就是這樣!這邊只剩下一個問題:你使用的是標準的乘法運算符。也許你會感到有一點困惑。如果我們將它改成其他的操作方式會變得更好。

好吧,我們來看看我們怎麼來我們怎麼將它改造成客制化的運算子。

客制化的運算子

custom-operators

把下面的程式碼添加到playground檔案裡面去,並開始這方面的教學吧。

這裡到底發生了怎麼事情呢,我們一步一步的來說明它:

  1. 我們客製化的乘法運算符號的名字是**.
  2. 它的類型是infix 因為他是二進位的運算使用兩個運算子。
  3. 它將會由左至右來進行運算,所以他的結合方向(associativity)是往左邊。
  4. 它的優先權是150 – 同層級的優先權是標準的乘法計算,因為他是比較高優先權的運算子。

注意:這邊有更多關於運算子的優先級別結合方向的相關資料。

客製化運算子的函數原型跟我們標準版的非常相近-只有名字不一樣:

這個函式的實作也跟先前的一模一樣:

我們來試看看客製化運算子的威力吧:

好了,就這樣!我們只剩下一個問題-這個運算子的複合版本到現在還沒定義,我們將在下一個章節解決這樣的問題。

複合運算子(compound operator)

compound-operators

這個複合運算子的類型,優先層級和結合方向跟我們先前提到的案例一樣-只有命名不同

接著我們添加複合運算子(compound operator)的原型函式在(playground)內:

這個函數沒有返回類型,因為他左邊的運算元inout

只有一件事情你應該在函式的本體裡面完成-使用我們先前已經建構好的客製化的運算子定義來回傳乘法結果:

現在,讓我們來測試我們建構好的運算子吧:

好了,沒有其他更簡單的方式了!

恭喜你

運算子重載,再謹慎地使用下,可以非常的強大-我希望你可以方法可以讓他在你專案中被使用到。

作為參考,你可以 下載Playground 檔案在GitHub上。我已經在Xcode 7.3 跟Swift 2.2的環境中測試過了。

如果你對於這個教學課程或以及運算子重載(operator overloading)有任何見解,請在下面留言並分享你的想法。

Credit: 本文內使用到的漫畫由MakeBeliefsComix.com.所設計的
譯者簡介:黃凱揚-系統分析與資深程式設計師,畢業南台科技大學電子系,曾在人力資源相關領域進行系統開發,13年的系統開發整合經驗,近年來協助客戶行 App 軟體以及 WebBase系統開發與系統分析與整合。

原文An Introduction to Operator Overloading


<p>Cosmic Pupăză 在部落格 cosminpupaza.wordpress.com 分享有關 Swift 和 iOS 開發文章,以及參與了 raywenderlich.com 和 appcoda.com 兩個平台的 Swift 教學團隊。平日喜歡玩結他和研究二戰歷史。可以透過電郵:[email protected],在Facebook,Twitter 及 Google+ 找到 Cosmic。</p>

blog comments powered by Disqus
訂閲電子報

訂閲電子報

AppCoda致力於發佈優質iOS程式教學,你不必每天上站,輸入你的電子郵件地址訂閱網站的最新教學文章。每當有新文章發佈,我們會使用電子郵件通知你。

已收你的指示。請你檢查你的電郵,我們已寄出一封認證信,點擊信中鏈結才算完成訂閱。

Shares
Share This