swift簡單總結(十六)—— 函數

版本記錄

版本號 時間
V1.0 2017.07.27

前言

我是swift2.0的時候開始接觸的,記得那時候還不是很穩定,公司的項目也都是用oc做的,并不對swift很重視,我自己學了一段時間,到現在swift3.0+已經出來了,自己平時也不寫,忘記的也差不多了,正好項目這段時間已經上線了,不是很忙,我就可以每天總結一點了,希望對自己對大家有所幫助。在總結的時候我會對比oc進行說明,有代碼的我會給出相關比對代碼。
1. swift簡單總結(一)—— 數據簡單值和類型轉換
2. swift簡單總結(二)—— 簡單值和控制流
3. swift簡單總結(三)—— 循環控制和函數
4. swift簡單總結(四)—— 函數和類
5. swift簡單總結(五)—— 枚舉和結構體
6. swift簡單總結(六)—— 協議擴展與泛型
7. swift簡單總結(七)—— 數據類型
8. swift簡單總結(八)—— 別名、布爾值與元組
9. swift簡單總結(九)—— 可選值和斷言
10. swift簡單總結(十)—— 運算符
11. swift簡單總結(十一)—— 字符串和字符
12. swift簡單總結(十二)—— 集合類型之數組
13. swift簡單總結(十三)—— 集合類型之字典
14. swift簡單總結(十四)—— 控制流
15. swift簡單總結(十五)—— 控制轉移語句

函數 - Functions

函數是swift的重點,函數用來完成特定任務的獨立的代碼塊,可以給一個函數起一個名字,當函數執行的時候,這個名字就會被“調用”。swift的函數風格很靈活,可以像C風格的參數,也可以像OC風格的參數,參數可以提供默認值,簡化函數調用,參數也可以既當做傳入參數,也可以當做傳出參數,也可以說,一旦函數執行結束,傳入的參數值可以被修改。

swift中,每個函數都有一個類型,包括函數的參數值類型和返回值類型,你可以把函數類型當做任何其他普通變量類型一樣處理,這樣可以簡單的把函數當做別的函數的參數,也可以從其他函數中返回函數,函數的定義可以寫在其他函數定義中,這樣可以在嵌套函數范圍內實現功能封裝。

下面主要講下面幾個大問題:

  • 函數的定義與調用 (Defining and Calling Functions)
  • 函數參數與返回值 (Function Parameters and Return Values)
  • 函數參數名稱 (Function Parameter Names)
  • 函數類型 (Function Types)
  • 函數嵌套 (Nested Functions)

函數定義與調用 - Defining and Calling Functions

定義一個函數時,可以定義一個或者多個有名稱和類型的值,作為函數的輸入,也可以定義一種類型的值作為函數執行結束的輸出。每一個函數都有一個名字,用來描述執行的任務,可以通過函數的名字調用函數。

下面我們就看一個簡單的例子。

class JJSwiftVC: UIViewController
{

    override func viewDidLoad()
    {
        super.viewDidLoad()
        
        view.backgroundColor = UIColor.lightGray
        
        print(greeting(personName: "Nana"))
    }
    
    func greeting(personName : String) -> String {
        return "Hello," + personName + "!"
    }
}

下面看輸出結果

Hello,Nana!

函數參數與返回值 - Function Parameters and Return Values

swift可以有任意類型任意個數的參數,函數也可以作為參數傳入,同時,swift可以有任意類型的返回值,函數也可以作為返回值,也可以沒有返回值,總之,非常靈活。

1. 多重輸入參數 - Multiple Input Parameters

函數可以有多個輸入參數,寫在圓括號中,用逗號分隔。

下面看一個簡單的程序。

class JJSwiftVC: UIViewController
{
    override func viewDidLoad()
    {
        super.viewDidLoad()
        
        view.backgroundColor = UIColor.lightGray
        
        print(calculateDistance(start: 1, end: 100))
    }
    
    func calculateDistance(start : Int, end : Int)  -> Int {
        return end - start
    }
}

下面看一下輸出結果

99

2. 無參函數 - Functions Without Parameters

函數可以沒有參數,這時候的函數名稱后面的圓括號里面就是空的。

class JJSwiftVC: UIViewController
{

    override func viewDidLoad()
    {
        super.viewDidLoad()
        
        view.backgroundColor = UIColor.lightGray
        
        print(greeting())
    }
    
    func greeting() -> String {
        return "Hello!"
    }
}

下面看輸出結果

Hello!

3. 無返回值函數 - Functions Without Return Values

函數可以沒有返回值,看下面的例子,相當于OC中返回類型為void的方法。

class JJSwiftVC: UIViewController
{

    override func viewDidLoad()
    {
        super.viewDidLoad()
        
        view.backgroundColor = UIColor.lightGray
        
        greeting(greet: "Nancy")
    }
    
    func greeting(greet : String) {
        print("Hello, " + greet)
    }

}

下面看輸出結果

Hello, Nancy

注意:嚴格講,雖然沒有返回值被定義,greeting函數依然返回了值,沒有定義返回類型的函數會返回特殊的值,叫Void,它其實是一個空的元組(tuple),沒有任何元素,可以寫成()。函數就算有返回值也可以忽略不用,但是有返回值的函數必須返回一個值。

4. 多重返回值函數 - Functions with Multiple Return Values

可以使用元組tuple類型讓多個值作為一個復合值從函數中返回,下面看一個簡單例子。

class JJSwiftVC: UIViewController
{

    override func viewDidLoad()
    {
        super.viewDidLoad()
        
        view.backgroundColor = UIColor.lightGray
        
        let number = count(string: "swift is very interesting !")
        print(number.vowels)
        print(number.consonants)
        print(number.others)
    }
    
    func count(string : String) ->(vowels : Int, consonants : Int, others : Int) {
        var vowels = 0, consonants = 0, others = 0
        for character in string.characters {
            switch String(character).lowercased() {
            case "a", "e", "i", "o", "u":
                vowels += 1
            case "b", "c", "d", "f", "g","h", "j", "k", "l", "m", "n", "p", "q", "r", "s", "t", "v", "w", "x", "y", "z":
                consonants += 1
            default:
                others += 1
            }
        }
    
        return(vowels, consonants, others)
    }
}

下面看輸出結果

7
15
5

函數參數名稱 - Function Parameter Names

函數的參數一般都這么定義:參數名(parameter name)這些參數只能在函數體內部使用,不能在調用函數時使用,這種類型的參數名稱被稱為局部參數名(local parameter)

1. 外部參數名 - External Parameter Names

有時候,調用函數時,給每個參數命名是非常有用的,因為這些參數名可以指出各個實參的用途,如果你希望函數的使用者在調用函數時提供參數名字,那就需要給每個參數除了局部參數名外再定義一個外部參數名,外部參數名寫在局部參數名之前,用空格分開。還有幾點要注意:

  • 如果你提供了外部參數名,那么函數被調用時,必須使用外部參數名。
  • 當其他人讀你的代碼,函數參數意圖不是很明顯時,考慮使用外部參數名,如果函數參數名的意圖很清晰就不需要定義外部參數了。

下面看一個簡單代碼。

class JJSwiftVC: UIViewController
{

    override func viewDidLoad()
    {
        super.viewDidLoad()
        
        view.backgroundColor = UIColor.lightGray
        
        print(join(string: "Hello", toString: "world", withJoiner: "-"))
    }
    
    func join(string s1 : String, toString s2 : String, withJoiner joiner : String) -> String{
        return s1 + joiner + s2
    }
}

下面看輸出結果

Hello-world

2. 簡寫外部參數名 - shorthand External Parameter Names

如果你需要提供外部參數名,但是局部參數名已經寫好了,那么不用再修改了,你可以只寫一次參數名,并用#作為前綴,就表明這個參數可以作為局部參數名和外部參數名。

注意:上面是swift 3.0以前的功能,3.0以后已經被去掉了,這里還加上這個選項,是讓大家區別一下。

3. 默認參數值 - Default Parameter Values

你可以在函數體內為每個參數定義默認值,默認值被定義后,調用這個函數時可以忽略這個參數。下面看這個簡單例子。

class JJSwiftVC: UIViewController
{

    override func viewDidLoad()
    {
        super.viewDidLoad()
        
        view.backgroundColor = UIColor.lightGray
        
        print(join(string: "Hello", toString: "World", withJoiner: "-"))
        print(join(string: "Hello", toString: "World"))
    }
    
    func join(string s1 : String, toString s2 : String, withJoiner joiner : String = "&&") -> String{
        return s1 + joiner + s2
    }
}

下面看輸出結果

Hello-World
Hello&&World

可以發現:

  • 如果參數有默認值,調用如果傳值就用我們傳入的值,但是如果調用不傳值就用參數的默認值。
  • 將帶有默認值的參數放在函數參數列表的最后面,這樣可以保證函數調用時候,非默認參數的順序是一致的,同時可以清晰的看見相同的函數在不同情況下調用時顯的更為清晰。

4. 默認值參數的外部參數名- External Names for Parameters with Default

當你沒有給帶默認值的參數提供外部參數名時,swift 會自動提供外部名字,函數調用的時候,外部參數名必須使用。下面看例子。

class JJSwiftVC: UIViewController
{

    override func viewDidLoad()
    {
        super.viewDidLoad()
        
        view.backgroundColor = UIColor.lightGray
        
        print(join(string: "Hello", toString: "World", withJoiner: " - "))
    }
    
    func join(string : String, toString : String, withJoiner : String = "&&") -> String{
        return string + withJoiner + toString
    }
}

下面看輸出結果

Hello - World

注意:你也可以使用下劃線_作為默認值參數的外部參數名,這樣可以在調用時不用提供外部參數名,但是給帶默認值參數命名總是更加合適的。

5. 可變參數 - Variadic Parameters

一個可變參數可以接受一個或多個值,函數調用時,你可以用可變參數來傳入不確定數量的輸入參數,通過在變量類型后面加上...的方式定義可變參數。

下面我們看一個例子。


class JJSwiftVC: UIViewController
{

    override func viewDidLoad()
    {
        super.viewDidLoad()
        
        view.backgroundColor = UIColor.lightGray
        
        print(sum(numbers: 1, 3, 4))
        print(sum(numbers: 100, 300, 500))
    }
    
    func sum(numbers : Double...) -> Double{
        var total = 0.0
        for number in numbers {
            total += number
        }
        return total
    }
}

下面看輸出結果

8.0
900.0

還有幾點要注意:

  • 傳入函數的參數被當做這個類型的一個數組處理。
  • 一個函數最多只能有一個可變參數,而且它必須是參數表中最后的一個,這樣做的目的是為了避免函數調用出現歧義。
  • 如果一個函數有一個或者多個帶默認值的參數,而且還有一個可變參數,那么把可變參數放在參數表的最后。

6. 常量參數和變量參數 - Constant and Variable Parameter

函數參數默認是常量,在函數體內改變參數值會報錯,但是有的時候有傳入參數的變量值副本是很有用的,你可以通過指定一個或者多個參數為變量函數,從而避免自己在函數中定義新的變量,變量參數不是常量,你可以在函數體內部把它當做新的可修改副本來使用。

常量參數變為變量參數的方法就是在參數名前面加關鍵字var,說了這么多上面都是swift 3.0以前的寫法,那么swift 3.0以后怎么寫呢,看下面的例子。

class JJSwiftVC: UIViewController
{

    override func viewDidLoad()
    {
        super.viewDidLoad()
        
        view.backgroundColor = UIColor.lightGray
        
        var number = 10
        print(sum(number: &number, number2: 20))
    }
    
    func sum(number : inout Int, number2 : Int) -> Int {
        number += number2
        return number
    }
}

下面看輸出結果

30

可以看見,現在不用var而是用inout了,這里需要注意的就是inout的位置。

7. 輸入輸出函數 - InOut Parameters

有的時候我們想要一個函數可以修改參數的值,并且當函數調用結束后,這個參數仍可用,這個時候我們就要把這個參數定義為輸入輸出參數- In - Out Parameters。定義輸入輸出參數,需要在參數定義前加一個inout關鍵字,一個輸入輸出參數有傳入函數的值,這個值被函數修改,然后被傳出函數,替換原來的值。

下面看一個簡單的例子。

class JJSwiftVC: UIViewController
{

    override func viewDidLoad()
    {
        super.viewDidLoad()
        
        view.backgroundColor = UIColor.lightGray
        
        var number1 = 10
        var number2 = 20
        swap(&number1, &number2)
        print(number1)
        print(number2)

    }
    
    func swapNumbers(a : inout Int, b : inout Int){
        let temp = a
        a = b
        b = temp
    }
}

下面看輸出結果

20
10

這里大家要注意inout的位置,放在類型說明之前,冒號之后。


函數類型

每一個函數都有函數類型,由函數參數類型和返回值類型組成。例如(Int, Int) -> Int它的意義就是:這個函數類型是,它有兩個Int型的參數,并返回一個Int型的值。

下面我們看幾種情況。

1. 使用函數類型 - Using Function Types

swift中,使用函數類型就像使用其他類型一樣,例如你可以定義一個類型為函數的常量或者變量,并將函數賦值給它。

var mathFunction = (Int, Int) -> Int = addInts

上面這個讀作:定義一個叫做mathFunction的變量,類型是一個有兩個Int型的參數并返回一個Int型的值的函數,并將這個新變量指向addInts函數。

有了這個定義,以后你可以使用mathFunction調用被賦值的函數了,比如:

mathFunction(2, 3)

有相同類型的不同函數可以被賦值給同一個變量,就像非函數類型的變量一樣,比如:

mathFunction = multiplyTwoInts

這里multiplyTwoIntsaddInts函數類型是相同的。

像其他數據類型一樣,當賦值一個函數給常量或者變量的時,swift用來推斷其函數類型。

let anotherMathFunction = addInts

這里anotherMathFunction類型也被推斷為 (Int, Int) -> Int。

2. 函數類型作為參數類型 - Function Types as Parameter Types

這里函數類型作為參數類型并不傳入函數是如何實現的,它只關心這個傳入的函數類型是否正確,下面看一個簡單的例子。

class JJSwiftVC: UIViewController
{

    override func viewDidLoad()
    {
        super.viewDidLoad()
        
        view.backgroundColor = UIColor.lightGray

        multiply(sum: sum, a: 1, b: 2)
    }
    
    func multiply(sum : (Int, Int) -> Int, a : Int, b : Int) {
    
        let result = sum(a, b) * a * b
        print("result = \(result)")
    }
    
    func sum(a : Int, b : Int) -> Int {
        return a + b
    }

}

下面看輸出結果

result = 6

3. 函數作為返回類型 - Functions Type as Return Types

你可以用函數類型作為另一個函數的返回類型,你需要做的是在返回箭頭->后寫一個完整的函數類型。

可以看下面這個例子。

class JJSwiftVC: UIViewController
{
    
    var currentValue = 10;

    override func viewDidLoad()
    {
        super.viewDidLoad()
        
        view.backgroundColor = UIColor.lightGray
        
        while currentValue > 0 {
            let moveToZero = chooseStepFunction(input: currentValue > 0)
            var result = moveToZero(currentValue)
            print(result)
            currentValue -= 1
        }
    }
    
    func chooseStepFunction(input : Bool) -> (Int) -> Int {
        if input {
            return backForward
        }
        else {
            return stepForward
        }
    }
    
    
    func stepForward(input : Int) -> Int {
        return input + 1
    }
    
    func backForward(input : Int) -> Int {
        return input - 1
    }
}

下面看輸出結果

9
8
7
6
5
4
3
2
1
0

嵌套函數 - Nested Functions

前面介紹的函數都是全局函數,你也可以把函數定義在別的函數體中,這種函數叫做嵌套函數,嵌套函數對于外界來說是不可見的,但是可以被它們封閉函數(enclosing Function)調用,一個封閉函數也可以返回它的某一個嵌套函數,使得這個函數可以在其他域中被使用。

我們接著看一個例子。

class JJSwiftVC: UIViewController
{
    
    var currentValue = 10;

    override func viewDidLoad()
    {
        super.viewDidLoad()
        
        view.backgroundColor = UIColor.lightGray
        
        while currentValue > 0 {
            let moveToZero = chooseStepFunction(input: currentValue > 0)
            var result = moveToZero(currentValue)
            print(result)
            currentValue -= 1
        }
    }
    
    func chooseStepFunction(input : Bool) -> (Int) -> Int {
        
        func stepForward(input : Int) -> Int {
            return input + 1
        }
        
        func backForward(input : Int) -> Int {
            return input - 1
        }
        
        if input {
            return backForward
        }
        else {
            return stepForward
        }
    }
}

下面看輸出結果

9
8
7
6
5
4
3
2
1
0

后記

未完,待續~~~

小雪
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 228,197評論 6 531
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 98,415評論 3 415
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 176,104評論 0 373
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 62,884評論 1 309
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,647評論 6 408
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,130評論 1 323
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,208評論 3 441
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,366評論 0 288
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 48,887評論 1 334
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,737評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 42,939評論 1 369
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,478評論 5 358
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,174評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,586評論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,827評論 1 283
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,608評論 3 390
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 47,914評論 2 372

推薦閱讀更多精彩內容