import Foundation
/*闭包表达式***********************************************************/
// 1.sort 函数(The Sort Function)
//Swift 标准库提供了名为 sort 的函数,会根据您提供的用于排序的闭包函数将已知类型数组中的值进行排序。 一 旦排序完成, sort(_:) 方法会返回一个与原数组大小相同,包含同类型元素且元素已正确排序的新数组。原数组不 会被 sort(_:) 方法修改。
let names = ["Chris", "Alex", "Ewa", "Barry", "Daniella"]
//sort(_:) 方法需要传入两个参数:
//1.已知类型的数组
//2.闭包函数,该闭包函数需要传入与数组元素类型相同的两个值,并返回一个布尔类型值来表明当排序结束后 传入的第一个参数排在第二个参数前面还是后面。如果第一个参数值出现在第二个参数值前面,排序闭包函 数需要返回 true ,反之返回 false 。
func backwards(s1: String, s2: String) -> Bool {
return s1 > s2
}
var reversed = names.sort(backwards)
print(reversed)
// print ["Ewa", "Daniella", "Chris", "Barry", "Alex"]
//如果第一个字符串 ( s1 ) 大于第二个字符串 ( s2 ), backwards 函数返回 true ,表示在新的数组中 s1 应该出 现在 s2 前。 对于字符串中的字符来说,“大于” 表示 “按照字母顺序较晚出现”。 这意味着字母 "B" 大于字 母 "A" ,字符串 "Tom" 大于字符串 "Tim" 。 其将进行字母逆序排序, "Barry" 将会排在 "Alex" 之前。
// 2.闭包表达式语法(Closure Expression Syntax)
//闭包表达式语法有如下一般形式:
//{ (parameters) -> returnType in
// statements
//}
reversed = names.sort({ (s1:String, s2:String) -> Bool in
return s1 > s2
})
print(reversed)
//需要注意的是内联闭包参数和返回值类型声明与 backwards 函数类型声明相同。 在这两种方式中,都写成了 (s 1: String, s2: String) -> Bool 。 然而在内联闭包表达式中,函数和返回值类型都写在大括号内,而不是大括号 外。
//闭包的函数体部分由关键字 in 引入。该关键字表示闭包的参数和返回值类型定义已经完成,闭包函数体即将开始。
//因为这个闭包的函数体部分如此短以至于可以将其改写成一行代码:
reversed = names.sort( { (s1: String, s2: String) -> Bool in return s1 > s2 } )
//因为排序闭包函数是作为 sort(_:) 方法的参数进行传入的,Swift可以推断其参数和返回值的类型。 sorted 期望 第二个参数是类型为 (String, String) -> Bool 的函数,因此实际上 String , String 和 Bool 类型并不需要作为闭 包表达式定义中的一部分。 因为所有的类型都可以被正确推断,返回箭头 ( -> ) 和围绕在参数周围的括号也可以 被省略:
reversed = names.sort( { s1, s2 in return s1 > s2 } )
// 3.单表达式闭包隐式返回(Implicit Return From Single-Expression Clossures)
reversed = names.sort({ s1, s2 in s1 > s2 })
//在这个例子中, sort(_:) 方法的第二个参数函数类型明确了闭包必须返回一个 Bool 类型值。 因为闭包函数体只 包含了一个单一表达式 ( s1 > s2 ),该表达式返回 Bool 类型值,因此这里没有歧义, return 关键字可以省略。
// 4.参数名称缩写(Shorthand Argument Names)
//Swift 自动为内联函数提供了参数名称缩写功能,您可以直接通过 $0 , $1 , $2 来顺序调用闭包的参数。
reversed = names.sort({ $0 > $1})
// 5.运算符函数(Operator Functions)
//实际上还有一种更简短的方式来撰写上面例子中的闭包表达式。 Swift 的 String 类型定义了关于大于号 ( > ) 的 字符串实现,其作为一个函数接受两个 String 类型的参数并返回 Bool 类型的值。而这正好与 sort(_:) 方法的 第二个参数需要的函数类型相符合。
reversed = names.sort(>)
/*尾随闭包***********************************************************/
//如果您需要将一个很长的闭包表达式作为最后一个参数传递给函数,可以使用尾随闭包来增强函数的可读性。尾随闭包是一个书写在函数括号之后的闭包表达式,函数支持将其作为最后一个参数调用。
func someFunctionThatTakesAClosure(closure: () -> Void) {
// 函数体部分
}
// 以下是不使用尾随闭包进行函数调用
someFunctionThatTakesAClosure({
// 闭包主体部分
})
// 以下是使用尾随闭包进行函数调用
someFunctionThatTakesAClosure(){
// 闭包主体部分
}
//注意: 如果函数只需要闭包表达式一个参数,当您使用尾随闭包时,您甚至可以把 () 省略掉。
//在上例中作为 sorted 函数参数的字符串排序闭包可以改写为:
reversed = names.sort(){$0 > $1}
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, 5033]
//您现在可以通过传递一个尾随闭包给 numbers 的 map 方法来创建对应的字符串版本数组。 需要注意的是调用 numbers.map 不需要在 map 后面包含任何括号,因为其只需要传递闭包表达式这一个参数,并且该闭包表达式参数通过尾随方式进行撰写:
let strings = numbers.map{
(var number) -> String in
var output = ""
while number > 0 {
output = digitNames[number % 10]! + output
number /= 10
}
return output
}
print(strings)
// strings 常量被推断为字符串类型数组,即 [String]
// 其值为 ["OneSix", "FiveEight", "FiveOneZero"]
//注意: 字典 digitNames 下标后跟着一个叹号 (!),因为字典下标返回一个可选值 (optional value),表明即使 该 key 不存在也不会查找失败。 在上例中,它保证了 number % 10 可以总是作为一个 字典的有效下标 key。 因此叹号可以用于强制解析 (force-unwrap) 存储在可选下标项中的 类型值。
/*捕获值***********************************************************/
func makeIncrementor(forIncrement amount: Int) -> () -> Int {
var runningTotal = 0
func incrementor() -> Int {
runningTotal += amount
return runningTotal
}
return incrementor
}
//makeIncrementor 返回类型为 () -> Int 。 这意味着其返回的是一个函数,而不是一个简单类型值。 该函数在 每次调用时不接受参数只返回一个 Int 类型的值。
//下面代码为一个使用 makeIncrementor 的例子:
let incrementByTen = makeIncrementor(forIncrement: 10)
print("incrementByTen is \(incrementByTen())")
print("incrementByTen is \(incrementByTen())")
print("incrementByTen is \(incrementByTen())")
let incrementBySeven = makeIncrementor(forIncrement: 7)
print("incrementByTen is \(incrementBySeven())")
print("incrementByTen is \(incrementByTen())")
//注意: 如果您将闭包赋值给一个类实例的属性,并且该闭包通过指向该实例或其成员来捕获了该实例,您将创 建一个在闭包和实例间的强引用环。 Swift 使用捕获列表来打破这种强引用环。
/*闭包是引用类型***********************************************************/
//上面的例子中, incrementBySeven 和 incrementByTen 是常量,但是这些常量指向的闭包仍然可以增加其捕 获的变量值。 这是因为函数和闭包都是引用类型
//无论您将函数/闭包赋值给一个常量还是变量,您实际上都是将常量/变量的值设置为对应函数/闭包的引用。 上面 的例子中, incrementByTen 指向闭包的引用是一个常量,而并非闭包内容本身。
let alsoIncrementByTen = incrementByTen
print("incrementByTen is \(alsoIncrementByTen())")
// 返回的值为50