函數(shù)的返回值以及靈活多變的參數(shù)

本系列文章為個人學(xué)習(xí)筆記:禁止轉(zhuǎn)載

函數(shù),作為另外一項幾乎任何編程語言中都有的特性,我們在之前的內(nèi)容中其實已經(jīng)反復(fù)使用過了。那為什么又要把它單獨拿出來作為一個系列呢?因為,除了封裝邏輯、傳參、調(diào)用、獲取結(jié)果這種最基礎(chǔ)的用法之外,Swift中的函數(shù)還有很多設(shè)計上的特性以及使用經(jīng)驗,值得我們理解和掌握。
作為開始,在這一節(jié)中,我們就快速回顧一下Swift中函數(shù)的最基本要素,這將是我們接下來所有內(nèi)容的基礎(chǔ)。如果你認(rèn)為自己已經(jīng)比較熟悉Swift函數(shù)的基本用法,大可以跳過這一節(jié);否則,就跟著我們開始吧。
一個最簡單的函數(shù)
一個最簡單的函數(shù),看上去是這樣的:

func printName() {
    print("My name is Mars")
}

其中:
func是定義函數(shù)的關(guān)鍵字,后面是函數(shù)名;
()中是可選的參數(shù)列表,既然是最簡單的函數(shù),自然我們可以讓它留空;
()后面,是函數(shù)的返回值,同樣,簡單起見,我們也沒有定義返回值;
{}中是函數(shù)要封裝的邏輯,其實,在這里,我們調(diào)用的print,也是一個函數(shù),只不過,它是一個定義在標(biāo)準(zhǔn)庫中的函數(shù),并且?guī)в幸粋€參數(shù)罷了;
定義好函數(shù)之后,我們就可以直接像這樣,來調(diào)用它:

printName() // My name is Mars

就可以在控制臺看到My name is Mars的打印結(jié)果了。
向函數(shù)傳遞參數(shù)
當(dāng)然,上面這個最簡單的函數(shù)除了演示用法外,并沒有任何實際意義。我們定義函數(shù)當(dāng)然不是為了反復(fù)在控制臺打印同樣的內(nèi)容。為了使用同樣的邏輯加工不同的數(shù)據(jù),第一個要做的事情,就是定義函數(shù)參數(shù)。例如,為了計算兩個整數(shù)的乘積:

func mul(m: Int, n: Int) {
    print(m * n)
}

然后,我們通過下面這樣來使用mul:

mul(m: 2, n: 3) // 6

就可以在控制臺看到打印的結(jié)果6了。
理解參數(shù)的兩種名稱
在Swift里,函數(shù)的參數(shù)實際上有兩個名字,一個用于在定義函數(shù)的時候使用,叫做argument name,一個用于在調(diào)用函數(shù)時使用,叫做argument label。
但是,其實我并不是很喜歡這個稱呼,因為我經(jīng)常搞混name和label,誰用在定義,誰用在調(diào)用。因此,我更喜歡管定義的時候使用的名稱叫做internal name,表示在函數(shù)內(nèi)部使用;而管調(diào)用的時候使用的名稱叫做external name,表示在函數(shù)外部使用。而在下面的例子里,我也會使用這兩個名字。
在我們的mul例子中,m和n,就是internal name,默認(rèn)情況下,如果不特別定義external name,它和internal name則是相等的?;蛘?,我們也可以像這樣,來自定義external name:

func mul(multiplicand m: Int, of n: Int) {
    print(m * n)
}

然后,我們就必須使用mul的external name來調(diào)用它了:
mul(multiplicand: 2, of: 3) // 6
或者,如果你不需要在函數(shù)調(diào)用的時候,使用external name,就要在定義函數(shù)的時候,在external name的位置,明確使用_表示忽略:

func mul(_ m: Int, of n: Int) {
    print(m * n)
}

然后我們就可以這樣使用mul了:

mul(2, of: 3)

在Swift 3里,函數(shù)的第一個參數(shù)不再默認(rèn)缺省忽略external name,它和函數(shù)的其他參數(shù)是一樣的。
所以,除了站在語法的角度來理解這兩個名稱之外,我們也可以從一個更實際的角度來理解它們:
External name為了讓函數(shù)在調(diào)用的時候,呈現(xiàn)更好的語義;
Internal name為了讓函數(shù)在實現(xiàn)的時候,呈現(xiàn)更好的實現(xiàn)邏輯;
如果internal name可以兼顧兩者,你也就無須再單獨定義external name了。
為參數(shù)設(shè)置默認(rèn)值
除了參數(shù)名之外,另一個我們會經(jīng)常處理的問題,是參數(shù)的默認(rèn)值。它可以用來約束函數(shù)的默認(rèn)行為,或者簡化絕大多數(shù)時候都會傳遞的值。例如:

func mul(_ m: Int, of n: Int = 1) {
    print(m * n)
}

當(dāng)我們這樣使用mul時:
mul(2) // 2
就會計算2 * 1的結(jié)果,并在控制臺看到2。
擁有默認(rèn)值的函數(shù)參數(shù)必須從右向左依次排列,有默認(rèn)值的參數(shù)不能出現(xiàn)在無默認(rèn)值的參數(shù)的左邊。
定義可變長參數(shù)
接下來,如果我們要計算不確定個數(shù)參數(shù)的乘積該怎么辦呢?Swift還允許我們通過下面的方式,定義可變長度的參數(shù)列表:

func mul(_ numbers: Int ...) {
    let arrayMul = numbers.reduce(1, *)
    print("mul: \(arrayMul)")
}

在上面的例子中,我們用numbers: Int...的形式,表示函數(shù)可以接受的Int參數(shù)的個數(shù)是可變的。實際上,numbers的類型,是一個Array<Int>,因此,為了計算乘積,我們直接使用Array類型的reduce方法就好了。
定義好之后,我們可以這樣調(diào)用它:

mul(2, 3, 4, 5, 6, 7) // 5040

就能在控制臺看到打印的計算結(jié)果了。
定義inout參數(shù)
在Swift里,函數(shù)的參數(shù)有一個性質(zhì):默認(rèn)情況下,參數(shù)是只讀的,這也就意味著:
你不能在函數(shù)內(nèi)部修改參數(shù)值;
你也不能通過函數(shù)參數(shù)對外返回值;
先來看第一條:

func mul(result: Int, _ numbers: Int ...) {
    result = numbers.reduce(1, *) // !!! Error here !!!
    print("mul: \(result)")
}

在上面的實現(xiàn)里,函數(shù)的參數(shù)默認(rèn)是個常量,因此編譯器會提示你不能在函數(shù)內(nèi)部對常量賦值。然后再來看第二條:如果我們希望參數(shù)可以被修改,并且把修改過的結(jié)果返回給傳遞進(jìn)來的參數(shù),該怎么辦呢?
其實,很簡單,我們需要用inout關(guān)鍵字修飾一下參數(shù)的類型,明確告訴Swift編譯器我們要修改這個參數(shù)的值:

func mul(result: inout Int, _ numbers: Int ...) {
    result = numbers.reduce(1, *) // !!! Error here !!!
    print("mul: \(result)")
}

然后,就可以這樣來使用mul了:

var result = 0
mul(result: &result, 2, 3, 4, 5, 6, 7)
result // 5040

注意到了沒?對于inout類型的參數(shù),我們在調(diào)用函數(shù)的時候,也需要在參數(shù)前明確使用&。這樣,mul執(zhí)行結(jié)束后,就可以看到result的值,變成了5040。
通過函數(shù)返回內(nèi)容
當(dāng)然,通過參數(shù)來獲取返回值只能算函數(shù)的某種副作用,更“正統(tǒng)”的做法,應(yīng)該是把返回值放在函數(shù)的定義里,像這樣:

func mul(_ numbers: Int ...) -> Int {
    return numbers.reduce(1, *)
}

我們通過-> Type的方式,在參數(shù)列表后面定義返回值。然后,就可以用mul的返回值,來定義變量了:

let result = mul(2, 3, 4, 5, 6, 7) // 5040
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容