1. 程式人生 > >swift 筆記 (七) —— 閉包

swift 筆記 (七) —— 閉包

閉包 閉包是個自包含的,可以在程式碼中傳遞的“塊”。。。好吧,不糾結定義,繼續。 swift的閉包,有點像C和Objective-C語言裡的 程式碼塊 {……}  閉包可以捕捉並且儲存在它所被定義的那個東西的上下文中定義的常量和變數。 事實上,在上一個筆記——函式,中的全域性函式和巢狀函式,全都是閉包的特殊形式。 全域性函式——是一個帶有函式名的,並不捕捉任何值的函式。 巢狀函式——是一個帶有函式名的並且從它被定義的外層函式中捕捉數值的函式。 閉包表示式——是一個不帶函式名的,使用一種輕便的語法書寫方式,並且可以從它被定義的外層函式中捕捉數值的函式。 從上面三個型別的函式的描述,可以看出,其實所謂的閉包(閉包表示式),就是一個不帶函式名的巢狀函式,只不過,他的書寫方式有點特別罷了。
swift 的閉包,鼓勵我們把他寫得短小並且希望沒有廢話的方式。。。我們都懂的,這種所謂的精巧小巧短小盡量沒有廢話的方式,有時候會讓人發狂,這正是閉包,這個玩意的難於理解之處吧! 不過,沒關係,官方給的文件,足以讓我們從一個讓正人類能讀懂的函式開始,慢慢變成一個非人正人類也可能會抓狂的函式的特殊形式——閉包。 剛才說到閉包推薦我們把函式儘量優化到所謂的短小和沒有廢話,那麼先看一下,哪些部分會被“優化”掉: 1. 能夠根據上下文推理出來的引數 以及 函式的返回值型別 2. 只有一條語句構成的簡單表示式的”return"關鍵字 3. 變數的名字 4. Trailing closure syntax (後關閉的語法: 這個東西,我沒有找到適合的解釋,我自己的理解它類似於僅僅在函式的結尾才有返回的方式,也就是在任何一個函式體內,任何一個分支都不會打斷函式的執行,一直到函式的最後一行的一個return或者無返回值之類的)
在swift的基本庫中,有一個叫作sort的函式,它可以給Array中的元素排序,然後返回一個與傳入的Array一樣型別和元素個數的新的Array。 sort的原型: sort(array: T[], pred: (T, T) -> Bool)  //這是個泛型, pred是它內部用的,不用管,總之,引數2是個函式 如果引數2是個函式,這個不理解的話,還是先回頭去把函式那部分複習一遍吧 這樣可能不太容易讀,那麼我把它變形一下: sort(myArray: Int[],  (Int, Int) -> Bool)  //這是個Int型的處理方式 (感謝 swift技術交流第一平臺(355277)的群友 packy(974871365) 指出之前寫的時候,sort的右括號被我弄丟了,現在改好了 )
sort的第一個引數是個Int型陣列, 第二個引數是個函式,這個函式有兩個引數,返回值是Bool型 當然我們也可以把原型中的T換成其它的型別,比如: sort(myArray: String[],  (String, String) -> Bool) sort(myArray: Double[], (Double, Double) -> Bool) 以此類推,隨便換成我們想要的形式 (泛型的意義如此) let names = [“Chris”, “Alex”, “Ewa”, “Barry”, “Daniella”] func myCompareFunc (s1: String, s2: String) -> Bool {   // 這個函式,跟sort的引數2 函式原型一樣      return s1 > s2 } var reversedNames = sort(names, myCompareFunc)  //得到了一個字母序倒序的陣列 到這裡,應該都很容易理解了,sort的第一個引數,是個String陣列, 第二個引數是個有兩個引數並且返回Bool型的函式 sort會把names陣列中的元素,按著它已經寫好了的演算法,取出某兩個下標的值,然後傳入到第二個引數定義的那個函式中,而第二個引數的函式是我們寫的,如果引數1> 引數2,就返回true,這裡是字串,返回的字母表中字母的順序,b排在a後面,所以b > a是true 前面說了,閉包有點像C語言和Objective-C裡面的“程式碼塊”, 所以,閉包的形式是這樣的: {                                                       //程式碼塊開始      (引數) -> 返回值型別 in              //注意這個語法: in 之後就是函式體了           函式體 }                                                       //程式碼塊結束 更前面的時候,已經說了,閉包沒有函式名。。。所以上面根本就沒有函式名,但他仍然是個函式。 我們用閉包的形式,來改寫上面寫過的sort的呼叫,以及 myCompareFunc的定義: reversedNames = sort(names,  //引數2在下面 {                                                       //程式碼塊開始      (s1: String, s2: String) -> Bool in     //注意這個語法: in 之後就是函式體了           return s1 > s2                          }                                                       //程式碼塊結束// sort呼叫結束 這裡sort的第二個引數,已經被我們替換成了上面提到的閉包的形式了 現在,我把一些換行符和一些空格以及註釋刪掉,僅僅是刪換行和空格和註釋哦: reversedNames = sort(names, {(s1:String, s2:String)->Bool in return s1 > s2} )  //對比一下,我沒有多刪東西吧 因為,這個閉包中的所有的引數型別(與sort的第一個引數的基本型別相同) 以及返回值型別(sort要求第二個函式的返回值型別為Bool),全都是可以推斷出來的,所以,型別可以省略,於是上面的這一條呼叫,就變成了: reversedNames = sort(names, {s1, s2 in return s1 > s2} )  //我只刪了引數型別和返回值型別 在上面的紅字部分,提到,閉包中,可以省略的東西,2.只有一條語句構成的簡單表示式的”return”關鍵字, 所以,我們繼續把return這個關鍵字也刪掉, sort的呼叫就變成了: reversedNames = sort(names, {s1, s2 in s1 > s1}) (感謝 swift蘋果開發超級群(191026105)的群友 阿康ゞ(409767959) 指出這裡第二個變數筆誤 ) reversedNames = sort(names, {s1, s2 in s1 > s2})
到這裡,是不是sort已經變得不太容易讀了。。。但還沒完: 對於inline的閉包, swift還提供了Shorthand Argument Names,作為引數的簡寫,以省去引數名,  $0代表第一個引數,$1代表第二個引數, $2……. 甚至連 in 都可以省了, 於是 sort呼叫的新版本: reversedNames = sort(names, {$0 > $1}) 操作符函式 上面的sort呼叫已經夠短了,但是對於操作符 > 來說,它需要的是兩個引數,並且返回值為Bool型,這正好符合了sort函式第2個引數所要求的函式形式,於是,我們可以把 > 當作函式,直接放在sort的第2個引數位置: reversedNames = sort(names, >)          //人類已經無法阻止閉包的簡化了...... 關於操作符作為函式,如果並不瞭解操作符過載的話,確實不好理解,那麼請問度娘:“操作符過載” 是什麼吧 Trailing Closures 如果,閉包表示式作為函式的最後一個引數的時候,閉包表示式又很長,不能像上面寫成那麼短的形式的話,那麼,可以把閉包表示式,寫在函式呼叫的外面,也就是()的後面,或者是下面: func myCallClosure(closure: () -> ()) {          //引數是個函式,名字叫closure而已。。。      closure()              //用引數的名字closure, 呼叫傳入的函式 } myCallClosure({})          //我只是放了個空閉包{}在這裡 如果{}中的內容很長,我們可以把{}放在()外面: myCallClosure() { } 這個看起來非常像函式的定義了,但他不是,因為函式名前面沒有 func關鍵字。 現在,我們回來看看sort,他的函式定義,也是最後一個引數要求傳入函式,所以,我們可以把剛剛的sort,變成: reversedNames = sort(names) { $0 > $1 }    //我覺得,連closure他爹都很難一眼看出來了。。。 我記得前幾天,有群友,帖了這樣一段程式碼,問:這是什麼意思,今天,我才知道他一定是沒有好好讀手冊!!!!!看下他帖的程式碼:
通過上面閉包的學習,現在是不是很容易看懂這個程式碼就是個閉包了? 只不過map後面沒有寫() 至於這個numbers.map是怎麼用的(numbers是個Array,map是Array的方法),這段程式碼的詳細意思,手冊上都有非常詳盡的講解,我就不列在這裡,也不要再問這個問題了,不要搞得好像自己學習能力很差一樣。。。 Capturing Values 早些時候,提到了閉包可以捕捉並儲存它的外層函式的常量和變數,接下來,我們來看看,有什麼神奇的事情,如果上面的閉包內容都理解了之後,這一段,其實沒啥好說的,直接上官方程式碼:

incrementor是個巢狀函式, 它返回了一個Int, 但是神奇的是,他沒有傳入引數,而是使用了一個叫作runningTotal的外層函式makeIncrementor定義的一個區域性變數,當makeIncrementor返回incrementor函式的時候,實際上是返回了incrementor函式的一個複製出來的實體函式(每次呼叫makeIncrementor的時候都會複製一個新的incrementor函式), 正因為閉包可以儲存它外層函式定義的常量和變數,所以,當外層函式的作用域已經不存在的時候,它依然可以使用那個常量或變數的值:

看到每次呼叫 incrementByTen(),得到的結果在遞增了吧? 

這一段,也證明了我上面的猜:每次呼叫makeIncrementor的時候都會複製一個新的incrementor函式 閉包是引用型別

這裡並沒有呼叫 makeIncrementor去複製一個新的函式,而僅僅是定義了一個變數 alsoIncrementByTen 被賦值成了 incrementByTen //這個函式在上面的時候,已經被呼叫了多次,正因為閉包是引用型別,這裡的alsoIncrementByTen實際上只是 incrementByTen 引用的那個之前複製出來的函式的新引用而已,於是,得到的結果是50.

相關推薦

swift 筆記 () ——

閉包 閉包是個自包含的,可以在程式碼中傳遞的“塊”。。。好吧,不糾結定義,繼續。 swift的閉包,有點像C和Objective-C語言裡的 程式碼塊 {……}  閉包可以捕捉並且儲存在它所被定義的那個東西的上下文中定義的常量和變數。 事實上,在上一個筆記——函式,中的

swift文件筆記() -- (Closures)

閉包是自包含的函式程式碼塊,可以在程式碼中被傳遞和使用。Swift中的閉包與 C和 Objective-C中的程式碼塊(b  locks)以及其他一些程式語言中的匿名函式比較相似。函式和閉包都是引用型別。 1.閉包表示式語法 閉包表示式語法有如下的一般形式:

Swift學習筆記

pps eap animate nbsp ssi apps arr 全局 mef 簡介 (真的很簡) 閉包的完整形態是這個樣子的: { (parameters) -> returnType in statements } 寫在一行裏就是

Swift學習筆記7——(Closures)

其實這個閉包可以看做是匿名的函式。 我們先來回想一下函式作為引數的情況 //定義一個函式,它最後的引數是一個函式型別 func doMath(first: Int, second: Int, mathFunc: (Int, Int) -> Int) { pr

swift 關於 尾隨 筆記

override func viewDidLoad() { super.viewDidLoad() self.weisuibibao(index: 12, bibao: {

JavaScript踩坑筆記09---、回撥函式

閉包: 簡單點說,閉包就是一個倉庫,它的作用就是將我們要用的區域性變數暫時儲存起來。 舉例說明。 // 定義一個函式fn,其中有一個區域性變數num function fn() { var num = 10; } 以上例子中,我們在函式fn中定義了一個變數num,所以變數的n

JavaScript教程筆記(8)-函式和IIFE

1 閉包 閉包(closure)是JavaScript語言的一大特色,也是一個難點。理解閉包,首先要理解變數作用域。 作用域有兩種:全域性作用域和函式作用域。函式內部可以訪問全域性變數。 var n = 999; function f() { console.log(

晝貓筆記 JavaScript --

  本次主要內容是 閉包 閱讀時間: 約 3分鐘 記得點個贊支援支援我哦 初步瞭解 先看下程式碼,輸出結果是多少?   1 function fn1 () { 2 var a = 2 3 function fn2 () { 4

python筆記3 裝飾器 叠代器 生成器 內置函數 初識遞歸

叠代 bsp 裝飾 turn () col python 生成器 對象 閉包 1, 閉包是嵌套在函數中的 2, 閉包是內層函數對外層函數的變量(非全局變量)的引用(改變) 3,閉包需要將其作為一個對象返回,而且必須逐層返回,直至最外層函數的返回值 閉包例子: def a1

Swift之自動(@autoclosure、@noescape、@escape、??)

@autoclosure(自動閉包) 1:自動閉包,顧名思義是一種自動建立的閉包,用於包裝函式引數的表示式,可以說是一種簡便語法. 2:自動閉包不接受任何引數,被呼叫時會返回被包裝在其中的表示式的值。 

Python學習筆記

閉包的基本定義 在電腦科學中,閉包(英語:Closure),又稱詞法閉包(Lexical Closure)或函式閉包(function closures),是引用了自由變數的函式。這個被引用的自由變數將和這個函式一同存在,即使已經離開了創造它的環境也不例外。所以,有另一種說法認為閉包是由函式和與其相關的引用

Swift-非逃逸

非逃逸閉包 //當一個閉包作為引數傳到一個函式中,但是這個閉包在函式返回之後被執行,我們稱該閉包從函式中逃逸。當你定義接受閉包作為引數的函式時,可以在引數名之前標註@noescape,用來指明這個閉包

Swift基礎:將改為逃逸型場景

alt+左鍵 檢視型別 常量 // 定義常量 let a = 10 let b = 20.5 // 常量運算 (X) let result = a + b Binary operator ‘+’ cannot be applied to

題目筆記,深複製和淺複製,原生js實現Promise)

就面試筆試題的一些筆記: 閉包( 實現add(2)(5) ) 深複製和淺複製 原生js實現Promise △ –>閉包知識: 實現add(2)(5) function add (x) { return functio

swift中解決迴圈引用的幾種方式

import UIKit class ViewController: UIViewController { // VC --strong -- 閉包 // 閉包- strong -- VC

Python學習筆記——利用寫遞增函式

*前言:這篇算是一個總結筆記 利用閉包返回一個計數器函式,每次呼叫它返回遞增整數: 建立生成器: def createCounter(): def f(): x = 0

wift學習筆記

根據上一節的例子,我們講解此次閉包的編寫 上節例子: 【格式】 {(引數名稱:引數型別)->返回型別 in 閉包函式體} 【舉例】 【閉包函式簡化】 1.由於AutoAdd函式中addFunc這個引數的傳入引數型別和返回型別為Int,那

JS筆記--探討中內部函式在各情況下的可訪問範圍

         閉包是指有權訪問另一個函式作用域中的變數的函式,通過通過在一個函式中建立的另一個函式而獲得閉包。首先要說明的是,閉包並不等於匿名函式,匿名函式可以構成閉包,但不等於閉包。          閉包的作用域,曾一直是困擾我多天的問題。為什麼在某些情況下,閉包只

swift-總結】

其實閉包就是函式 作為條件的函式 閉包表示式 首先宣告一個數組 var names = ["Charis", "Alex", "Ewa", "Barry", "Daniella"] 將這個陣列按照字母排序 宣告一個閉包函式 func bac

[Swift4] Swift筆記 2.0(函式2,,列舉,結構體)

函式,閉包,列舉,結構體 函式多值返回 // 利用 元組 返回多個值 // 利用 陣列 輸入多個值 func calcMaxmain( values :[Int])-> (max :