Apple在Swift的網站上是這麼形容的:
Swift。全新程式語言,讓人人可創作精彩 App。
由於iPhone帶動了智慧型手機的風行,也因此開創了一個新的產業:APP開發,近幾年來,我們發現HTML5、Javascript和Object-C等等這些在以往相當冷門的語言突然變得很熱門,各種專門課程和教學書籍手冊如雨後春筍般到處都是,周遭的親朋好友若知道你會寫程式,總不忘會再多問一句「那你會不會寫APP?」,彷彿寫APP是現代資訊人必備的行頭之一。
如果你想開始瞭解一下APP怎麼寫的,也很不幸選了Apple的iOS作為入門的試金石,而且堅持一定原生的(註一),那麼第一次接觸Object-C的經驗肯定讓你苦惱不已,它是源自於C語言,但語法結構又不太一樣,還有一大堆的減號、中括號和大量來自於賈伯斯被趕出Apple自創NextStep公司時代的 NS****函式庫,很多人第一次接觸時便被這些火星文給嚇到而放棄了,轉而學起Java或較易入門的HTML5和JavaScript。
但語言本應是愈簡單愈好,一個困難到要花費很長的時間和精力才能搞懂學會的語言,它永遠沒有普及的一天,而且也達不到所謂語言的最終目的:溝通;目前我們所處的科技時代,人與機器的溝通方式就是透過程式語言,這個產業要進步,唯有讓更多的人擁有與機器溝通的能力,因此,簡化語言就是最好的方式,蘋果為了讓iOS設備能夠普及世界,在Object-C問世20多年後,終於推出全新的語言Swift,強調簡單易學,一如它的口號:「讓人人可創作精彩 App」
在Swift官網上還提到最令我感興趣的一點,Swift的執行速度竟然比Object-C更快(約2.6倍),大為扭轉一般人對scripting語言慢吞吞的刻板印象,光是這點就值得馬上放棄Object-C改學Swift了。(註二)
在學習一個新的程式語言時,我們一開始都會先去知道常數和變數的用法、資料的型別表示方法、再來瞭解其基本運算的指令,不過在此我先略過這幾個部份而直接從函式開始,原因是Swift的語法與一般的scripting語言相當近似,所以這些部份在語法上皆大同小異,只要有基本的scripting基礎,你甚至先略過這部份也沒有關係,或者你也可以先到此網站http://numbbbbb.gitbooks.io/-the-swift-programming-language-/content/看一下;而Swift函式的用法則稍微特別一點,因此我將從這部份開始介紹。
函式
基本語法
Swift中的函式很靈活,當它獨立存在時,即我們常見的全域函式,也可以存在於別的函式之中,形成巢狀函式,還可以存在於類別、結構和列舉之中,就是我們俗稱的方法。
Swift函式語法格式:
func 函式名稱(參數列及型別) -> 回傳值型別 {
指令…
return 回傳值
}
JavaScript等的scripting語言,函式宣告是不一定需要指定傳入參數型別和回傳值型別的,而且很少用到->之類的字元,不過Swift需要,可以看出Swift雖然號稱簡單,但還是比起一般的scripting語言嚴謹,這是我們需要先熟悉的地方;不過,如果沒有回傳值時,這個->和回傳值型別是可以省略的。下方是一個無回傳值的函式格式,跟一般常見的函式格式很像。
func 函式名稱(參數列及型別) -> {
指令…
}
接下來,我們來看一個計算長方型面積函式rectangleArea的例子:
func rectangleArea(width:Double, height:Double) -> Double {
let area = width * height
return area
}
println(“320x480的長方形面積:\(rectangleArea(320,480))”)
使用外部參數名稱
我們在呼叫函式時經常會傳入多組的參數,但我們經常會忘了這些參數的功能和意義,如果我們在每個傳入的參數前能有個說明,那麼這個程式碼就更為清楚易懂;例如,上面的計算長方型面積函式rectangleArea,我們是這樣呼叫的:
println(“320x480的長方形面積:\(rectangleArea(320,480))”)
或許您猜得到320和480分別代表長與寬,但是卻無法確定那一個是長那個是寬,而且,如果未來傳入的參數愈多,我們就會愈難分辨每個參數的目的與用途,因此,建議您可以使用「外部參數名稱」,將每個參數賦予一個有意義的變數名稱。
例如,原先的函式是長這樣子:
func rectangleArea(width:Double, height:Double) -> Double {
let area = width * height
return area
}
weight與height都是內部函式,只能用在rectangleArea函式裏面,加入外部函式名稱後,函式的寫法變成如下:
func rectangleArea(W width:Double, H height:Double) -> Double {
let area = width * height
return area
}
呼叫此函式的時候,我們便可以加上變數名稱:
println(“320x480的長方形面積:\(rectangleArea(W:320, H:480))”)
這樣在使用函式時,是不是就很清楚了呢?
不過,你可能會想到,可不可以內部與外部參數都使用相同的名稱height與weight比較方便呢?可以的,我們只要在變數前加上#符號即可,例如:
func rectangleArea(# width:Double, #height:Double) -> Double {
let area = width * height
return area
}
呼叫函式的方法一樣,代入參數名稱即可:
println(“320x480的長方形面積:\(rectangleArea(weight:320, height:480))”)
如此一來,我們便很容易看出函式中各個參數的功用和目的,雖然在撰寫時會多了些功夫,但是對後續的修改和維護卻方便了不少。
函式重載
函式重載是指多個相同名稱的函式但是接收的參數型別不同,例如,我們可以定義多組相同名稱的函式,分別接受不同類型的參數,舉例如下:
func receive(I : Int) {
println( “接收一個Int型別的資料 i=\(i)” );
}
func receive(d : Double) {
println( “接收一個Double型別的資料 d=\(d)” );
}
func receive(x :Int, y:Int) {
println( “接收二個Int型別的資料 x=\(x) y=\(y)” );
}
func receive(i :Int) ->Int {
println( “接收一個Int型別的資料 i=\(i), 回傳值型別是 Int” );
}
此時,假設我們執行a1:Int = receive(10),會呼叫最後一個函式,若執行a1:()= receive(10)或a1:Void= receive(10),則會呼叫第一個函式。那麼,a1()= receive(10, 10) 呢?應該是第三個。
函式回傳
您看得出來下方函式的用法嗎?
func getArea( type : String ) -> ( Double, Double ) -> Double {
指令…
}
我們要分段來看才能明白
函式名稱和參數是:func getArea( type : String )
回傳的則是:( Double, Double ) -> Double
代表了這個函式的回傳值是另一個函式的型式。
請參考下方的例子便更能明白函式回傳的用法(有點繁複):
//函式:計算長方形面積
func rectangleArea( width:Double, height:Double ) -> Double {
let area = width * height
return area
}
//函式:計算三角形面積
func triangleArea( bottom:Double, height:Double ) -> Double {
let area = 0.5 * bottom * height
return area
}
//函式:判斷形狀並回傳面積計算公式
func getArea( type : String ) -> ( Double, Double ) -> Double {
var returnFunction( Double, Double ) -> Double //先定義好要回傳的函式型別
switch (type) {
case “rect”:
returnFunction = rectangleArea
case “tria”:
returnFunction = triangleArea
default:
returnFunction = rectangleArea
}
return returnFunction
}
使用:
var area : ( Double, Double ) = getArea( “tria” )
println( “三角型面積:\(area(10,15))” )
註一:用HTML5或JavaScript等第三方程式撰寫後再Complier為原生碼,或在WebView模擬瀏覽器的環境下執行。
註二:Objective-C較慢的原因:其實Objective-C是在 C 上面架構了簡單的一層, Objective-C 語法會在 compile time 時編譯成 C,每個 Objective-C 物件其實都是一個指向某個 C structure 的指標,物件的成員就是 structure 中的變數,至於物件的 method 則是會編譯成 C function,然後 runtime 中會有一個表格,管理一個 C 字串對應到 function pointer 的對應,我們對某個物件呼叫某個 method 的時候,就是用 method 的名稱(又稱為 selector)去尋找對應的 function 執行。(摘自http://zonble.net/archives/2014_08/1616.php)