本文首發於個人我的博客html
eg: 咱們有一個函數 sumgit
// 函數
func sum(_ v1: Int, _ v2: Int) -> Int { v1 + v2 }
// 使用
sum(10, 20)
複製代碼
若是用閉包表達式定義一個函數github
var fn = {
(v1: Int, v2: Int) -> Int in
return v1 + v2
}
// 使用
fn(10, 20)
複製代碼
固然了,也能夠編程
{
(v1: Int, v2: Int) -> Int in
return v1 + v2
}(10, 20)
複製代碼
總結起來就是swift
{
(參數列表) -> 返回值類型 in 函數體代碼
}
複製代碼
咱們定義以下的函數 exec ,它接收三個參數,分別爲兩個Int 和一個函數,並且這個函數,接收兩個Int 參數,返回一個Int結果,exec 的做用就是,把前兩個參數傳給第三個參數(也就是函數)去執行,而後結果打印出來數組
// 函數 咱們定義以下的函數 exec ,它接收三個參數,分別爲兩個Int 和一個函數,並且這個函數,接收兩個Int 參數,返回一個Int結果,exec 的做用就是,把前兩個參數傳給第三個參數(也就是函數)去執行,而後結果打印出來
func exec(v1: Int, v2: Int, fn: (Int, Int) -> Int) {
print(fn(v1, v2))
}
複製代碼
若是用閉包表達式來定義的話bash
// 閉包表達式
exec(v1: 10, v2: 20, fn: {
(v1: Int, v2: Int) -> Int in
return v1 + v2
})
複製代碼
固然了,咱們能夠省略不少,以下閉包
// 省略參數類型 由於swift能夠本身推斷類型
exec(v1: 10, v2: 20, fn: {
v1, v2 in return v1 + v2
})
// return 也能夠省略
exec(v1: 10, v2: 20, fn: {
v1, v2 in v1 + v2
})
// 省略掉參數列表,用$0表明第0個參數,$1表明第1個參數
exec(v1: 10, v2: 20, fn: {
$0 + $1
})
// 終極省略
exec(v1: 10, v2: 20, fn: +)
複製代碼
有以下的函數 閉包表達式做爲函數的最後一個實參app
func exec(v1: Int, v2: Int, fn: (Int, Int) -> Int) {
print(fn(v1, v2))
}
複製代碼
使用尾隨閉包爲函數
exec(v1: 10, v2: 20) {
$0 + $1
}
複製代碼
// 這個閉包表達式表達式是函數的惟一實參
func exec(fn: (Int, Int) -> Int) {
print(fn(1, 2))
}
複製代碼
可使用尾隨閉包以下
// 使用尾隨閉包以下三種均可以
exec(fn: { $0 + $1 })
exec() { $0 + $1 }
exec { $0 + $1 }
複製代碼
假設咱們有個包含Int元素的數組,想對立面的元素進行排序
func numberSort() {
var arr = [6, 8, 1, 10]
arr.sort()
print(arr) //[1, 6, 8, 10]
}
numberSort()
複製代碼
打印結果爲
[1, 6, 8, 10]
查看官方對sort的源碼爲
// 官方代碼
func sort(by areInIncreasingOrder: (Element, Element) -> Bool)
複製代碼
假如咱們想自定義排序
/// 返回true: i1排在i2前面
/// 返回false: i1排在i2後面
func cmp(i1: Int, i2: Int) -> Bool {
// 大的排在前面
return i1 > i2
}
複製代碼
使用的時候
var nums = [6, 8, 1, 10]
nums.sort(by: cmp)
print(nums)
複製代碼
打印結果爲
[10, 8, 6, 1]
上面的代碼
能夠寫成
nums.sort(by: {
(i1: Int, i2: Int) -> Bool in
return i1 > i2
})
複製代碼
也能夠等價於下面幾種
nums.sort(by: { i1, i2 in return i1 > i2 })
nums.sort(by: { i1, i2 in i1 > i2 })
nums.sort(by: { $0 > $1 })
nums.sort(by: > )
nums.sort() { $0 > $1 }
nums.sort { $0 > $1 }
複製代碼
Swift中,不少時候,若是咱們對於參數不作處理,能夠用 下劃線 _ 來代替
例以下面的閉包
func exec(fn: (Int, Int) -> Int) {
print(fn(1, 2))
}
print(exec{_,_ in 100 }) // 100
複製代碼
輸出
100
假設咱們定義一個這樣的函數,要求 若是第1個數大於0,返回第一個數。不然返回第2個數
func getFirstPositive(_ v1: Int, _ v2: Int) -> Int? {
return v1 > 0 ? v1 : v2
}
//調用
getFirstPositive(10, 20) // 10
getFirstPositive(-2, 20) // 20
getFirstPositive(0, -4) // -4
複製代碼
如今假如說,咱們這麼傳入的話
func getNum() -> Int {
// 這裏每次都執行
let a = 100
let b = 200
return a + b
}
func getFirstPositive2(_ v1: Int, _ v2: Int) -> Int? {
return v1 > 0 ? v1 : v2
}
getFirstPositive2(10, getNum())
複製代碼
由於第一個參數已是10 大於0了,第二個參數,也就是getNum() 根本不必去執行,浪費性能,因此,有沒有什麼辦法能作到,當第一個參數不知足時候,纔去執行getNum()呢?答案是有的
// 改爲函數類型的參數,可讓v2延遲加載
func getFirstPositive2(_ v1: Int, _ v2: () -> Int) -> Int? {
// 這裏判斷 v1 > 0 不會調用 v2()
return v1 > 0 ? v1 : v2()
}
getFirstPositive2(10, {
// 第一個參數大於0的時候,這裏不會執行
let a = 100
let b = 200
return a + b
})
複製代碼
若是改爲這樣寫就報錯了
/ 改爲函數類型的參數,可讓v2延遲加載
func getFirstPositive2(_ v1: Int, _ v2: () -> Int) -> Int? {
// 這裏判斷 v1 > 0 不會調用 v2()
return v1 > 0 ? v1 : v2()
}
getFirstPositive2(10, 20) //報錯 Cannot convert value of type 'Int' to expected argument type '() -> Int'
複製代碼
由於須要的是() -> Int類型,給的是Int
咱們能夠寫成下面兩種均可以
/ 改爲函數類型的參數,可讓v2延遲加載
func getFirstPositive2(_ v1: Int, _ v2: () -> Int) -> Int? {
// 這裏判斷 v1 > 0 不會調用 v2()
return v1 > 0 ? v1 : v2()
}
getFirstPositive2(10) { 20}
getFirstPositive2(10, {20})
複製代碼
上面的也能夠用自動閉包技術
func getFirstPositive3(_ v1: Int, _ v2: @autoclosure () -> Int) -> Int? {
return v1 > 0 ? v1 : v2()
}
getFirstPositive3(-4, 20)
複製代碼
更多資料,歡迎關注我的公衆號,不定時分享各類技術文章。