Swift學習之十四:閉包(Closures)
/* 閉包(Closures) * 閉包是自包含的功能代碼塊,可以在代碼中使用或者用來作為參數傳值。 * 在Swift中的閉包與C、OC中的blocks和其它編程語言(如Python)中的lambdas類似。 * 閉包可以捕獲和存儲上下文中定義的的任何常量和變量的引用。這就是所謂的變量和變量的自封閉, * 因此命名為”閉包“("Closures)").Swift還會處理所有捕獲的引用的內存管理。 * * 全局函數和嵌套函數其實就是特殊的閉包。 * 閉包的形式有: * (1)全局函數都是閉包,有名字但不能捕獲任何值。 * (2)嵌套函數都是閉包,且有名字,也能捕獲封閉函數內的值。 * (3)閉包表達式都是無名閉包,使用輕量級語法,可以根據上下文環境捕獲值。 * * Swift中的閉包有很多優化的地方: * (1)根據上下文推斷參數和返回值類型 * (2)從單行表達式閉包中隱式返回(也就是閉包體隻有一行代碼,可以省略return) * (3)可以使用簡化參數名,如$0, $1(從0開始,表示第i個參數...) * (4)提供了尾隨閉包語法(Trailing closure syntax) */ // 下麵用Swift標準庫中的sort方法來一步步簡化閉包寫法 // sort函數需要兩個參數 // 參數一:數組 // 參數二:一個閉包:帶有兩個參數,這兩個參數類型與數組中的元素類型相同,返回值是Bool var names = ["Swift", "Arial", "Soga", "Donary"] // 第一種方式:使用函數 func backwards(firstString: String, secondString: String) -> Bool { return firstString > secondString // 升序排序 } // 這裏第二個參數,傳了一個函數 // reversed is equal to ["Swift", "Soga", "Donary", "Arial"] var reversed = sort(nams, backwards) // 第二種方式:使用閉包方式 // 完整閉包寫法是在花括號內有參數列表和返回值,用關鍵字in表明閉包體的開始 // (firstString: String, secondString: String) 閉包參數列表 // -> Bool 指明閉包返回值類型是Bool // in關鍵字表明閉包體的開始 reversed = sort(names, { (firstString: String, secondString: String) -> Bool in return firstString > secondString }) // 這裏可以進一步簡化寫法,因為閉包代碼比較短,可以寫到一行上 reversed = sort(names, { (firstString: String, secondString: String) -> Bool in return firstString > secondString}) // 下麵再進一步簡化寫法 :根據環境上下文自動推斷出類型 // 參數列表都沒有指明類型,也沒有指明返回值類型,這是因為swift可以根據上下文推測出 // firstString和secondString的類型會是names數組元素的類型,而返回值類型會根據return語句結果得到 reversed = sort(names, { firstString, secondString in return firstString > secondString}) // 再進一步簡化:隱式返回(單行語句閉包) // 因為閉包體隻有一行代碼,可以省略return reversed = sort(names, { firstString, secondString in firstString > secondString}) // 再進一步簡化:使用簡化參數名($i,i=0,1,2...從0開始的) // Swift會推斷出閉包需要兩個參數,類型與names數組元素相同 reversed = sort(names, { $0 > $1 }) // 最簡單的一種寫法:使用操作符 reversed = sort(names, >) /* * 尾隨閉包(Trailing Closures) * 如果函數需要一個閉包參數作為參數,且這個參數是最後一個參數,而這個閉包表達式又很長時, * 使用尾隨閉包是很有用的。尾隨閉包可以放在函數參數列表外,也就是括號外。如果函數隻有一個參數, * 那麼可以把括號()省略掉,後麵直接跟著閉包。 */ // Array的方法map()就需要一個閉包作為參數 let strings = numbers.map { // map函數後麵的()可以省略掉 (var number) -> String in var output = "" while number > 0 { output = String(number % 10) + output number /= 10 } return output } /* 捕獲值 * 閉包可以根據環境上下文捕獲到定義的常量和變量。閉包可以引用和修改這些捕獲到的常量和變量, * 就算在原來的範圍內定義為常量或者變量已經不再存在(很牛逼)。 * 在Swift中閉包的最簡單形式是嵌套函數。 */ func increment(#amount: Int) -> (() -> Int) { var total = 0 func incrementAmount() -> Int { total += amount // total是外部函數體內的變量,這裏是可以捕獲到的 return total } return incrementAmount // 返回的是一個嵌套函數(閉包) } // 閉包是引用類型,所以incrementByTen聲明為常量也可以修改total let incrementByTen = increment(amount: 10) incrementByTen() // return 10,incrementByTen是一個閉包 // 這裏是沒有改變對increment的引用,所以會保存之前的值 incrementByTen() // return 20 incrementByTen() // return 30 let incrementByOne = increment(amount: 1) incrementByOne() // return 1 incrementByOne() // return 2 incrementByTen() // return 40 incrementByOne() // return 3
最後更新:2017-04-03 07:56:58