我們之前把函數(shù)看做是代碼的邏輯單元,實際上不僅如此,函數(shù)還和我們用var或let定義的東西一樣,可以被賦值并且有類型呢!怎么樣?是不是感覺函數(shù)這家伙看似忠厚老實,其實背后還有故事?確實,函數(shù)背后面還有大大的故事呢。
1、函數(shù)是個什么
func printStr(str: String) {
print(str)
}
let anotherPrintStr = printStr
anotherPrintStr("Hello world") // 在控制臺輸出 "Hello world"
我們首先定義了一個函數(shù) printStr 接著我們把它賦值給了一個用let聲明的常量 anotherPrintStr,然后,然后,然后 anotherPrintStr 居然可以被當做一個函數(shù)進行調(diào)用了。這篇代碼看起來還是不夠明顯,讓我們繼續(xù)研究一下,我們應該還記得我們之前提前過的 類型推斷 機制吧,既然swift是一們靜態(tài)的強類型語言,那么它是不會允許常量 anotherPrintStr 沒有類型而存在,此時一定是類型推斷機制在暗中給 anotherPrintStr 賦予了類型,我們可以通過xcode幫助我們揪出這個類型是什么,這個類型就是: (String) -> Void
函數(shù)的類型是由 參數(shù)類型與返回值類型共同決定的,Void代表函數(shù)沒有返回值,如果一個函數(shù)既沒有參數(shù)也沒有返回值,那么該函數(shù)的類型應該是 () -> Void
那么也就是說我們可以用顯示聲明的方式來定義anotherPrintStr了。
let anotherPrintStr: (String) -> Void = printStr
anotherPrintStr("Hello world") // 在控制臺輸出 "Hello world"
這個時候我們已經(jīng)完全明白anotherPrintStr不過是一個函數(shù)類型的常量嗎,但是函數(shù)printStr到底是什么呢?我們嘗試用函數(shù)類型重新定義一下printStr。
let printStr: (String) -> Void = {str in
print(str)
}
printStr("Hello world") // 在控制臺輸出 "Hello world"
通過這段代碼我們可以這樣理解printStr,它是一個用let聲明的常量,類型是函數(shù)類型 (String) -> Void 它的值是一段可以執(zhí)行的代碼體(這是閉包的定義方式,我們可以暫時忽略)。也就是說和一個整形常量的區(qū)別在于,printStr的值可以被執(zhí)行。
2、函數(shù)是一類公民
我們可能早就聽說了,swift的函數(shù)是一類公民,這其實說的是函數(shù)與swift的其他類型一樣,并沒有受到歧視,而是得到了平等的對待,這包括賦值,傳遞,作為參數(shù)和返回值等。
func printStr(str: String) {
print(str)
}
func anewFunc(perform: (String) -> Void) -> (String) -> Void {
return perform
}
anewFunc(printStr)
我們定義了一個函數(shù) anewFunc 它接收一個 (String) -> Void 類型,并返回一個 (String) -> Void 類型。我們可以把函數(shù)作為參數(shù)傳遞給 anewFunc ,而該函數(shù)又將其做為返回值。
3、這一切都是為了啥
我們現(xiàn)在承認 函數(shù)確實能做為另外一個函數(shù)的參數(shù)和返回值,可是這折騰來折騰去的是為了啥呢?我想這應該有兩點原因。
寫代碼的一個重要目標是提高代碼的復用度,這同時也能標識一個程序員水平的高低,編程語言提供的抽象表達能力,以及我們經(jīng)常討論的各種設計模式都是在為了實現(xiàn)這一目標,如果函數(shù)能夠成為一等公民,那么意味著我們將獲得一種將模板與代碼行為分離的表達能力,這是一種很強的抽象表達能力,可以有效的提高代碼的復用度可以看另外一篇內(nèi)容來介紹閉包)。
所有我們聲明的內(nèi)容,都有其作用域和聲明周期,如果我們想打破其作用域和聲明周期,那么我們可以使用return語句或者是閉包(可以看另外一篇內(nèi)容來介紹swift的作用域)。