函式是每個程式語言都會有的一個語法,非常的實用,只要是編寫功能,一定與函式脫離不了關係,而函式的內容,主要會有幾個部分,也是這篇文章主要會提到的內容,本文章將分成幾個描繪function基礎功能的部分:
內部參數(internal parameter)、外部參數(external parameter)
省略參數(Omitting parameter)、默認參數(default parameter)、可變參數函式(Variadic functions)
函式的結構,主要會長這樣:
func someNoise(){
let message = "Oops!"
print(message)
}
someNoise()
如果有輸入參數的話,要記得在括弧內填入(參數:型別)
然後作為外部函式執行的時候,要記得函式(參數:型別)。
如果是有回傳值記號:->的話,則一定要記得Return一定要在下面加上去。
原則上,上面三種樣態是函式的最基礎樣貌。下面,則會進一步地提到函式在細節上的一些規則。
參數:內部參數(internal parameter)、外部參數(external parameter)
在上述提到函式可能產生的樣態,接著要說函式在使用上,具有的一些小規則:
在使用函式的時候,可以先把函式先想成兩個部分:內部、外部
內部:基本上就是func…{ }中,{}裡面的地方,就是內部,而所謂的內部參數,就是game:String的部分,因為他直接的對應到的是String的輸入。
外部:外部的部分,就是函式的呼叫,也就是game_commenrt(name:String)的部分,在上述的定義函式中,name這個字眼的意義就是外部參數,專門用在當函式作為是一個外面呼叫的字眼的時候,為了區分而使用的。
所以在上面這段程式裡面,name就是外部參數,game就是內部參數。
當然,假若你今天不想要額外的給定外部參數的名稱,也可以用另一種方式:底線“ _ ”來做作為省略外部參數
如下所述:
那也必須注意,既然都省略了外部參數的名稱了,那函數呼叫的時候,就不應該有外部參數的名字,直接把值輸進去就可以運行整個函式。
默認參數這件事情是建立在Bool值上的,如果在內部參數的部分,便認定goodgame的預設是true,那可以看到以下會發生的選擇路徑:
根據第一個呼叫函式的樣態,game_comment()只需要放置外部參數的內容即可,Swift基本上會默認參數就是true,所以就直接走向回傳第一個值。
而根據第二個呼叫函式的樣態,game_comment()則是給定了外部參數額外的goodgame:false,所以既然特意給定了,就代表會影響Swift對於呼叫函式的認定,因而回傳第二個值。
可變參數函數的內容其實是像下面這樣的,如果Int給上了“…”就代表了可以接受多個值,而numbers就是接收了2,3,12這三個值
因此走訪了這幾個數字之後,就得出了下面的結果:
接著,我們要談兩種函式不一樣的功能:
你可以看到outsideFunction裡面承載了三個參數:
第一個是someFunction、第二個是a ,
第二個是b,
而三者共同建構出打印的字串:”Result(someFunction(a, b))”
這個時候,我們到外部來看,我們呼叫outsideFunction,然後就把三個參數個字塞了進去:insideFunction、4、50三個參數。
你看到了嗎?insideFunction可以這樣做為參數被使用的,但要記得它的型別!不然你就得debug了
我們可以看到在someFunction這個函式,它參數型別設定是傳入布林值,傳出函式型別(Int)->Int,而這個函式要我們返回一個三元運算子的運算,三元運算子的內容是這樣:假若Bools是true,則走returnFunctionA,false,則走returnFunctionB。
ok,這個時候下面的someFunction(number>0)就是一個比大小的機制,它拿number來比,結果就是大,結果為true。
下面true就傳入了finalFunction,既然傳入值是true,那勢必就選了returnFunctionA作為內部的另一個函式,所以這個時候,finalFunction(10)的10就是returnFunctionA的傳入參數了。
原則上,我們在過往所及的函式皆為全域函式(global function),意即:你今天只要寫好了某個函式,那它在你的編譯器中,都是可以被使用、應用的。
而第三者巢狀函式則有不同,如果我們要描述它的結構,可以暸解到:巢狀函式就是一個函式包著函式的狀態,裡面的函式只能被包在外部的函式應用,也可以被當作返回值返回其他地方使用。
以下將以上述所及的三個重點作為主要說明:
如果將函式建立在另一個函式中,稱作巢狀函式(nested function),被建立在其內的函式只能在裡面使用,也可以當做返回值返回以讓其他地方也可以使用。
意即:我們在函式A裡面建構的另一個函式B,函式B只能在函式A裡使用
巢狀函式的邏輯我就不再多說了,因為它大部分的程式碼跟2.函式作為返回值的部分是幾乎一模一樣的,只是把someFunction移到最前面,然後讓下面returnFunctionA、returnFunctionA兩者縮排到someFunction的作用域裡面。
這樣就可以知道,誰是這個函式的老大,誰是小弟。
100Days of Swift中,大概對拋出函式有了這樣的概念的描述:
Sometimes functions fail because they have bad input, or because something went wrong internally. Swift lets us throw errors from functions by marking them as throws before their return type, then using the throw keyword when something goes wrong.
翻譯翻譯:有時候函式的失敗,是因為他們在輸入的時候就發生錯誤了,或者有些東西在內部就錯了,Swift讓我們藉由標記throws拋出錯誤,因此我們使用throw這個關鍵字來表示有些東西錯了。
不過,在執行拋出錯誤之前,我們大抵上會先設定,什麼東西是錯誤的,因此,我們會先設置一個枚舉(Enum)來放置這些錯誤的提示,如下:
枚舉在設置這些錯誤的時候,會先等於一個Error的協定(Protocol,
這個在之後會談到),然後在「passwordProblem」的下面描述各式不同類型的錯誤。
而function則在這些錯誤的範例下,以拋出(throws)的關鍵字定義這個函式的運作方式,而如果都沒有符合的條件,就以拋出(throw)這個關鍵字來引入枚舉裡面定義錯誤問題的項目。
不過,拋出問題,總是要解決問題吧?
所以在拋出問題後,就會需要捕獲拋出的問題,因此,會使用do…catch的方式來把問題解決:
我們先來問一個問題:假若我們沒有處理錯誤,會發生什麼問題呢?
我這裡有一個從其他地方引述的相關解答:
如果遇到錯誤時會將錯誤拋出並傳遞至錯誤處理的地方,目前尚未定義怎麼處理錯誤,所以這時 Swift 會自動處理,不過這可能會導致程式中止,所以我們還是自行定義錯誤處理的方式。
而Swift針對錯誤,就有它處理的方式:
Swift 使用do-catch語句來定義錯誤的捕獲(catch)及處理,每一個catch表示可以捕獲到一個錯誤拋出的處理方式。
總之,就上述的例子,try後面接的是拋出函式的內容,以及要置入的值,後面的catch就是針對錯誤的返回的處理。如果要用公式來描述,會是下面這個樣子:
總之,這大概會是關於拋出函式最基礎的樣子,大致上再複述一下上面提到的內容:
會先定義好錯誤的可能項目:枚舉Enum會是一個不錯的方式
寫一個拋出函式,註記好throws的部分,以及從中延伸出的throw的內容
再用do…try…catch去處理錯誤的內容。
小記:本篇會有幾個基本小問題:
鐵人賽