位置:首頁 > 高級語言 > Swift教學 > Swift閉包

Swift閉包

在 Swift 中的閉包類似於結構塊,並可以在任何地方調用,它就像 C 和 Objective C 語言內置的函數。 函數內部定義的常數和變量引用可被捕獲並存儲在閉包。函數被視為封閉的特殊情況,它有 3 種形式。

全局函數 嵌套函數 閉合表達式
有名字但不捕獲任何值 有名字,從封閉函數捕捉值 無名閉包從相鄰塊捕獲值

在 Swift 語言閉合表達式,如下優化,重量輕語法風格,其中包括。

  • 推導參數並從上下文菜單返回值的類型

  • 從單封表達的隱性返回

  • 簡略參數名稱

  • 尾部閉包語法

語法

下麵是一個通用的語法定義用於閉包,它接受參數並返回數據的類型:

{(parameters) -> return type in
   statements
}

下麵是一個簡單的例子:

let studname = { println("Welcome to Swift Closures") }
studname()

當我們使用 playground 運行上麵的程序,我們得到以下結果

Welcome to Swift Closures

以下閉包接受兩個參數並返回一個布爾值:

{(Int, Int) -> Bool in
   Statement1
   Statement 2
    ---
   Statement n
}

下麵是一個簡單的例子:

let divide = {(val1: Int, val2: Int) -> Int in 
   return val1 / val2 
}
let result = divide(200, 20)
println (result)

當我們使用 playground 運行上麵的程序,我們得到以下結果

10

在閉包中的表達式

以便捷的方式命名來定義代碼塊可以通過嵌套函數實現的。取而代之代表整個函數聲明及名稱構造用來表示函數。代表函數的語法清晰,簡短聲明是通過封閉的表達來實現的。

升序排列程序

排序字符串是 Swift 中保留的函數 “sorted”,這是在標準庫中已提供實現。該函數將所述給定的字符串進行遞增順序排序並返回具有相同的尺寸,並在舊數組中相同數據類型的一個新的數組的元素。舊的數組保持不變。

兩個參數的排序在函數內部表示:

  • 已知類型的值表示為數組

  • 數組的內容 (Int,Int) ,並返回一個布爾值(Bool),如果數組排序不好就會返回true,否則將返回false。

普通函數帶輸入字符串被寫入,並傳遞給排序函數獲得字符到新的數組,如下麵所示:

func ascend(s1: String, s2: String) -> Bool {
   return s1 > s2
}
let stringcmp = ascend("swift", "great")
println (stringcmp)

當我們使用 playground 運行上麵的程序,我們得到以下結果

true

最初的數組排序給定為 "Swift" 和 "great"。函數用來數組排序被聲明為字符串數據類型,並且返回類型為布爾型。 兩個字符串進行比較,並以升序排序,並存儲在新的數組。如果排序執行成功,該函數將返回true;否則將返回 false。

閉包表達式語法用法

  • 常量參數

  • 可變參數 和 inout 參數

閉包表達不支持的默認值。可變參數和參數元組也可以用來作為參數類型和返回類型。

let sum = {(no1: Int, no2: Int) -> Int in 
   return no1 + no2 
}
let digits = sum(10, 20)
println(digits)

當我們使用 playground 運行上麵的程序,我們得到以下結果

30

在函數聲明中提到的參數和返回類型聲明,也可通過使用 'in' 關鍵字內聯閉包表達式函數表示。 一旦聲明參數及其返回類型“in”關鍵字,則用於表示閉包體。

單一表達式隱式返回

在這裡,排序函數的第二個參數的函數類型明確指出,一個布爾值必須由閉包返回。因為閉包體內含有一個表達式(s1 > s2)返回一個布爾值, 不會出現歧義,其返回關鍵字可以省略。

要返回一個表達式語句在閉包中, “return” 關鍵字在其聲明部分被省略。

let count = [5, 10, -6, 75, 20]
var descending = sorted(count, { n1, n2 in n1 > n2 })
var ascending = sorted(count, { n1, n2 in n1 < n2 })

println(descending)
println(ascending)

當我們使用 playground 運行上麵的程序,我們得到以下結果

[75, 20, 10, 5, -6]
[-6, 5, 10, 20, 75]

該語句本身明確規定,當 string1 大於 string2 返回 true,否則為false,因此return語句省略。

已知類型的閉包

考慮兩個數相加。我們知道相加後將返回整數數據類型。因此,已知類型的閉包聲明

let sub = {(no1: Int, no2: Int) -> Int in 
   return no1 - no2 
}
let digits = sub(10, 20)
println(digits)

當我們使用 playground 運行上麵的程序,我們得到以下結果

-10

聲明簡寫參數名稱作為閉包

Swift 自動提供簡寫參數名內聯閉包, 可以使用由 $0,$1,$2 等等名稱,指的是封閉的參數值。

var shorthand: (String, String) -> String
shorthand = { $1 }
println(shorthand("100", "200"))

在這裡,$0 和 $1 參考閉包的第一和第二個字符串參數。

當我們使用 playground 運行上麵的程序,我們得到以下結果

200

Swift 方便用戶來表示內嵌閉包為縮寫參數名為:$0, $1, $2 --- $n.

閉包參數列表中被省略定義部分,當我們表示內部閉包表達式簡寫參數名。 根據函數類型簡寫參數名稱將被導出。由於簡寫參數表達體所定義的 'in' 關鍵字被省略。

閉包作為操作函數

Swift 提供了一種簡單的方法訪問的成員,隻需提供操作符函數作為閉包。 在前麵的例子關鍵字“Bool”是用來比較兩個字符串,相等返回“true”,否則返回“false”。

表達式即使在閉包中變得簡單在操作函數:

let numb = [98, -20, -30, 42, 18, 35]
var sortedNumbers = numb.sorted({
   (left: Int, right: Int) -> Bool in
      return left < right
})
let asc = numb.sorted(<)
println(asc)

當我們使用 playground 運行上麵的程序,我們得到以下結果

[-30, -20, 18, 35, 42, 98]

閉包作為尾隨包

傳遞這個函數的最後一個參數到閉合表達式使用“尾隨閉包”聲明。它使用 {} 寫在函數()外部。當它不能寫入函數內聯在一行上,使用它是需要。

reversed = sorted(names) { $0 > $1}

其中 {$0 > $1} 表示為外部(名稱)聲明尾隨閉包。

import Foundation
var letters = ["North", "East", "West", "South"]
 
let twoletters = letters.map({ (state: String) -> String in
   return state.substringToIndex(advance(state.startIndex, 2)).uppercaseString
})
let stletters = letters.map() { $0.substringToIndex(advance($0.startIndex, 2)).uppercaseString }
println(stletters)

當我們使用 playground 運行上麵的程序,我們得到以下結果

[NO, EA, WE, SO]

捕獲值和引用類型

在閉包的幫助下 Swift 完成捕捉常量和變量的值。它還參考修改值,即使常量和變量在閉包體已經不存。

捕獲常數和變量值是通過使用嵌套函數寫入函數,這是使用其它函數體來實現的。

一個嵌套函數捕獲

  • 外部函數參數

  • 捕捉常量和外部函數中定義的變量

Swift 中當常量或變量在函數中聲明,引用到變量也自動地被閉合創建。它也提供工具來引用兩個以上的變量作為同一閉合如下:

let decrem = calcDecrement(forDecrement: 18)
decrem()

在這裡,oneDecrement 和 遞減變量都指向同一個內存塊閉合參考。

func calcDecrement(forDecrement total: Int) -> () -> Int {
   var overallDecrement = 100
   func decrementer() -> Int {
      overallDecrement -= total
      println(overallDecrement)
      return overallDecrement
   }
   return decrementer
}
let decrem = calcDecrement(forDecrement: 18)
decrem()
decrem()
decrem()

當我們使用 playground 運行上麵的程序,我們得到以下結果:

82
64
46

當每一個外部函數 calcDecrement 調用時都會調用 decrementer()函數 並通過值 18 遞減,並在外部函數 calcDecrement 的幫助下返回結果。在這裡,calcDecrement 作為一個閉合。

即使函數 decrement()冇有任何參數,閉合默認情況下是指變量的"整體遞減“ “total” 通過獲取其值。為指定的變量的值副本被使用新的 decrementer()函數存儲。Swift 通過處理存儲器管理功能分配和釋放存儲器空間當變量在不使用。