swift學習之閉包(closure)

2021-07-04 06:44:39 字數 4073 閱讀 8535

swift的閉包和c,oc中block是差不多的,其實swift中的全域性和巢狀函式實際上也是一種特殊的閉包,閉包有三種形式:

(1)全域性函式是有乙個名字,但不能捕獲任何值的閉包

(2)巢狀函式是有乙個名字,可以捕獲在函式內的值得閉包

(3)閉包表示式是乙個輕量級的語法,可以從上下文中捕獲值

閉包表達是乙個乾淨,清晰,鼓勵簡介,優化的語法,優化包括:

(1)從上下文中推斷引數和返回型別

(2)簡單的閉包表達可以省略return

(3)簡寫引數名

(4)尾部閉包語法

(一)閉包表達

閉包表達就是以乙個簡明準確的方式寫乙個內聯包

(二)sort函式

swift標準庫提供了sort函式,用來排序已知型別的陣列,通過你提供的排序包規則輸出

let originalnames = ["chris","alex","ewa","barry","daniella"]

var currentnames = originalnames.sort(backwards)

func backwards(s1: string , s2: string) -> bool
這麼表達有點囧長啊(long-winded),但是在這這個栗子也算比較好和合適的

下面用閉包表達一下

var reverse = originalnames.sort()
解釋:(1)in前面的是引數型別和返回值型別

(2)in後面是實現部分

(3)整個表示式用{}號括起來

由於swift有推斷型別功能,閉包可以從上下文推斷型別,所以上面的表示式還可以寫成:

var reverse = originalnames.sort()

print(reverse)

另外,單行表示式可以忽略return關鍵字,所以上面的表示式又可以寫成:

var reverse = originalnames.sort()

print(reverse)

通過sort函式和sort的第二個引數我們就可知道這個函式一定是返回乙個bool型別,返回值只有乙個單一的表示式,所以return可以省略,並且不會造成歧義

(三)簡寫引數名

swift對於內聯包自動提供了引數名的簡寫,這些簡寫名用來關聯引數,那麼這些看不到簡寫名是怎麼簡寫的呢?就是$0,$1,$2....

如果你寫閉包表達用了簡寫名,那你寫的所有引數就可以省了,因為人家已經相當於給你提供了引數,只是簡寫了,就不用你寫了,寫了都tm浪費感情啊,不光浪費自己的,還浪費swift的,尤其是人家程式設計師的,我都把閉包簡成這樣了,你就不要寫那麼麻煩添亂了,省的大家都心裡堵得慌,廢話不多說了,下面檢測一下這個簡寫:

var reverse = originalnames.sort(  )

print(reverse)

0,1這個就是從第乙個引數開始關聯,大家都是幹程式的,知道程式排序都是從0開始吧,這個你在問為什麼,我就只能呵呵了

(四)操作符(有的也叫運算子)函式

由於swift的string型別有規定兩個字元的比較,並且返回的是bool型別,所以上面我們可以寫的再簡單點,直接傳乙個操作符(運算子),swift就會自己推斷呼叫string自身規定的實現

var reverse = originalnames.sort(>)

(五)trailing(尾部)閉包

意思就是把閉包實現放在尾部來寫,為什麼要放在尾部呢,因為閉包實現太長了,可能會影響**的可讀性,美觀性,所以就放在最後面實現好了

swift陣列有乙個map(對映)方法,僅僅是採用閉包表達作為引數像裡面傳遞的。這個閉包會遍歷陣列的每個元素,並且返回相應的可選型別的對映。對映的核心和返回值的型別都是又閉包規定的。當使用map方法後,會返回乙個新的陣列, 這個陣列包含了所有新的對映的值,下面舉乙個例子(把int型陣列轉換成strin型的陣列)說明一下:

let digitnames = [0:"zero",1:"one",2:"two",3:"three",4:"four",5:"five",6:"six",7:"seven",8:"eight",9:"nine"]

let numbers = [16,58,510]

let strings = numbers.map()

return output

}print(strings)

解釋:首先宣告乙個字典,在宣告乙個陣列,呼叫map方法,自己寫實現

其次,通過return,swift已經推斷strings是乙個字串型的陣列了

最後,就看列印結果了

如果閉包是函式的唯一引數,函式後面的括號可以省略,所以上面的函式還可以這麼寫:

let strings2 = numbers.map 

return output

}print(strings2)

在這裡,number前面使用var修飾的,這個在函式有講,就是在內部呼叫可變,相當於在函式內部宣告了乙個變數,並把number(陣列的元素)傳遞給了這個變數,函式呼叫結束,他也就釋放了

規定的返回型別是string型別,儲存在返回的陣列中了

注意:上面字典後面跟了乙個感嘆號,因為字典下標語法總是返回乙個可選值的如果查詢失敗的話,但是在上面的例子中,一定要確保字典下標值是有效地,因此我們要強制拆包,得到儲存在可選返回值的中的string型別值

(六)值捕獲

說白了,就是閉包可以從上下文中捕獲值,用為己用(變數常量都可以,還可以自己改變其值),下面舉乙個簡單的函式巢狀的例子

let incrementbyten = makeincrementer(forincrement: 10)

print(incrementbyten())

}func makeincrementer(forincrement amout: int) -> void -> int

return increment

}

func increment()這個函式就捕獲到了runningtotal和amout的值,makeincrementer這個函式返回的是乙個函式型別(乙個不接收引數且返回值型別為int型別的函式)

let incrementbyten = makeincrementer(forincrement: 10)

incrementbyten()

incrementbyten()

print(incrementbyten())

上面的列印結果猜一下是多少?這是因為閉包自動幫我們儲存了變數的值,調動同一函式會自動加,如果我們再定義乙個函式呢?比如下面兩個的輸出結果

let incrementbyseven = makeincrementer(forincrement: 7)

incrementbyten()

print(incrementbyten())

print(incrementbyseven())

由上面得知我們再定義乙個函式閉包會引用乙個新值給這個新的函式,和前面的函式不會混淆,而原始的還是執行自己的功能

注意:如果我們把乙個閉包定義成了類例項的屬性,通過引用這個例項或者它的成員,會產生乙個強引用,不過給了我們解決辦法,這個我會在後面學習之後進行講解,謝謝

(七)閉包是引用型別

在上面的例子中,incrementbyten和incrementbyseven是常量,但是他們引用的閉包仍然可以改變runningtotal的值,這是因為函式和閉包都是引用型別的,當我們把函式或者閉包賦給乙個常量或者變數時,實際上是我們用這個常量或者變數引用那個閉包,列印裡面呼叫了也算也用,在列印下面的**中runningtotal的值已經被+10了,

let alsoincrementbyten = incrementbyten
這裡面的alsoincrementbyten是incrementbyten+10的結果,不信可以自己嘗試下

好啦,閉包也講完了,下次我會介紹swift中的列舉

Swift 學習之閉包 Closures

swift 學習之閉包 closures 閉包 closures 1.閉包概念 閉包是功能性自包含模組,可以在 中被傳遞和使用。swift 中的閉包與 c 和 objective c 中的 blocks 以及其他一些程式語言中的 lambdas 比較相似。閉包可以捕獲和儲存其所在上下文中任意常量和變...

Swift學習之閉包Closures

原始碼位址 let learnios learnios 引數lan,in將引數與函式體隔開 let learn learn swift return為一行時可省了return let learn1 let result learn1 swiftui print result func findwor...

swift 學習《五》 閉包

函式 格式 引數列表 對外名內部使用名 引數型別,對外名內部使用名 引數型別 閉包格式 宣告乙個引數是閉包的函式 func 函式名 閉包名 引數名 引數型別 引數名 引數型別 返回值 呼叫 引數中帶閉包的函式 函式名 1,尾隨引數,沒有值的括號可省,沒有返回值是,in 都課省 2,in 的作用是,分...