本人已遷移博客至掘進,以后會在掘進平台更新最新的文章也會有更多的干貨,歡迎大家關注!!!https://juejin.im/user/588993965333309
在Swift中,可以通過func定義一個函數,也可以通過閉包表達式定義一個函數!
一、閉包表達式
概念
閉包表達式與定義函數的語法相對比,有區別如下:
- 去除了func
- 去除函數名
- 返回值類型添加了關鍵字in
- { }放在形參列表的前邊
閉包表達式的形式如下:
{ (參數列表) -> 返回值類型 in 函數體代碼 }
講解
舉例1 閉包表達式作為變量或者常量的值
調用閉包表達式不需要寫參數v1,v2,直接調用fn0(10,20)就可以
舉例2 閉包表達式作為函數的返回值
舉例3 閉包表達式作為函數的實參
下面講述sorted(by:)方法定義和語法優化方式,來展示閉包表達式不同的表達方式達到同樣的效果!
講述之前先簡單介紹下sorted方法, Swift標准庫提供了sorted(by:)方法,會將已知類型數組中的值進行排序. 一旦進行了排序會返回和原數組大小相同,包含同類型元素並且是正確排序的數組,如例3.
sorted(by:)方法接受一個閉包,該閉包函數需要傳入元素類型的兩個值,並返回Bool值,完成排序,排序閉包函數類型需為(String, String) -> Bool
在上面的兩種寫法中,都寫成了(String, String) -> Bool, 在閉包表達式中函數和返回值類型都寫在了大括號內,而不是大括號之外.
下面不斷簡化的如下
let arr = ["hello","world","guohai"] ///閉包表達式當做參數 //寫法一 let sortArr0 = arr.sorted{(str1: String, str2: String) -> Bool in return str1 < str2 } //寫法二: 省去了參數類型 let sortArr1 = arr.sorted{(str1, str2) -> Bool in return str1 < str2 } //寫法三: 如果返回值是單一表達式,可省去return let sortArr2 = arr.sorted{(str1, str2) -> Bool in str1 < str2 } //寫法四: 如果編譯器可以確定返回值,可以去除返回值類型 let sortArr3 = arr.sorted{(str1, str2) in str1 < str2 } //寫法四: Swift閉包表達式可以不明顯寫出參數名,可以用美元符$表示 let sortArr4 = arr.sorted{$0 < $1} //寫法五: 編譯器,對於$0 < $1和直接<效果一樣 let sortArr5 = arr.sorted(by: <)
尾隨閉包
如果將很長的閉包表達式作為函數的最后一個實參,使用尾隨閉包可以增強函數的可讀性
尾隨閉包是一個被書寫在函數調用括號外面(后面)的閉包表達式
如果閉包表達式是函數的唯一實參,而且使用了尾隨閉包的語法, 那就不需要在函數名后寫圓括號
二、閉包
閉包: 一個函數和它所捕獲的變量/常量環境組合起來
- 一般指定義在函數內部的函數
- 一般它捕獲的是外層函數的局部變量/常量
看如下閉包,返回的plus和num形成了閉包
typealias Fn = (Int) -> Int func getFn() -> Fn { var num = 0 func plus(_ i: Int) ->Int { num += i return num } return plus } var fn = getFn() print(fn(1)) print(fn(2)) print(fn(3)) print(fn(4))
如果大家看不出上面的結果,可以將var num = 0放在外面是全局變量,如下
全局變量num時,結果是不斷的疊加,如果還是回到上一個,將num = 0移植到函數內部變成局部變量,和plus形成閉包,結果又如何呢?
發現結果是一樣的,下面來探究本質!
查看上面代碼匯編代碼如下
上面四次fn操作,調用訪問的同一內存num,因為閉包的作用將局部變量num放進了堆空間,所以num不會被銷毀!
拓展:(iOS底層堆空間分配的大小是16的倍數--常識)