在线时间:8:00-16:00
迪恩网络APP
随时随地掌握行业动态
扫描二维码
关注迪恩网络微信公众号
一、闭包的介绍
闭包是自包含的函数代码块,可以在代码中被传递和使用。 Swift 中的闭包与 C 和 Objective-C 中的代码块(blocks)以及其他一些编程语言中的 lambdas 函数比较相似。 闭包可以捕获和存储其所在上下文中任意常量和变量的引用。 这就是所谓的闭合并包裹着这些常量和变量,俗称闭包。Swift 会为您管理在捕获过程中涉及到的所有内存操作。 全局和嵌套函数实际上也是特殊的闭包,闭包采取如下三种形式之一:
Swift 的闭包表达式拥有简洁的风格,并鼓励在常见场景中进行语法优化,主要优化如下:
二、示例1、sorted 函数,sorted函数需要传入两个参数: 已知类型的数组,闭包函数,该闭包函数需要传入与数组类型相同的两个值,并返回一个布尔类型值来告诉sorted函数当排序结束后传入的第一个参数排在第二个参数前面还是后面。如果第一个参数值出现在第二个参数值前面,排序闭包函数需要返回true,反之返回false 这是一个相当冗长的方式,本质上只是写了一个单表达式函数 (a > b) let names = ["Chris","Alex","Ewa","Barry","Daniella"] func backwards(s1:String, s2:String) -> Bool{ return s1 > s2 } var reverse = names.sort(backwards) print("降序:\(reverse)") 2、闭包表达式语法 闭包表达式语法有如下一般形式 { (parameters) -> returnType in statements } 闭包表达式语法可以使用常量、变量和inout类型作为参数,不提供默认值。 也可以在参数列表的最后使用可变参数。 元组也可以作为参数和返回值。 reverse = names.sort({ (s1:String, s2:String) ->Bool in return s1 < s2 }) print("升序:\(reverse)") 3、根据上下文推断类型 因为排序闭包函数是作为sorted函数的参数进行传入的,Swift可以推断其参数和返回值的类型。 sorted期望第二个参数是类型为(String, String) -> Bool的函数,因此实际上String,String和Bool类型并不需要作为闭包表达式定义中的一部分。 因为所有的类型都可以被正确推断,返回箭头 (->) 和围绕在参数周围的括号也可以被省略: 实际上任何情况下,通过内联闭包表达式构造的闭包作为参数传递给函数时,都可以推断出闭包的参数和返回值类型,这意味着您几乎不需要利用完整格式构造任何内联闭包。 reverse = names.sort({s1,s2 in return s1 > s2}) print("降序:\(reverse)") 4、单表达式闭包隐式返回 单行表达式闭包可以通过隐藏return关键字来隐式返回单行表达式的结果,如上版本的例子可以改写为 在这个例子中,sorted函数的第二个参数函数类型明确了闭包必须返回一个Bool类型值。 因为闭包函数体只包含了一个单一表达式 (s1 > s2),该表达式返回Bool类型值,因此这里没有歧义,return关键字可以省略。 reverse = names.sort({s1,s2 in s1 < s2}) print("升序:\(reverse)") 5、参数名称缩写 Swift 自动为内联函数提供了参数名称缩写功能,您可以直接通过$0,$1,$2来顺序调用闭包的参数。 如果您在闭包表达式中使用参数名称缩写,您可以在闭包参数列表中省略对其的定义,并且对应参数名称缩写的类型会通过函数类型进行推断。 in关键字也同样可以被省略,因为此时闭包表达式完全由闭包函数体构成: reverse = names.sort({ $0 > $1 })//在这个例子中,$0和$1表示闭包中第一个和第二个String类型的参数。 print("降序:\(reverse)") 6、运算符函数 实际上还有一种更简短的方式来撰写上面例子中的闭包表达式。 Swift 的String类型定义了关于大于号 (>) 的字符串实现,其作为一个函数接受两个String类型的参数并返回Bool类型的值。 而这正好与sorted函数的第二个参数需要的函数类型相符合。 因此,您可以简单地传递一个大于号,Swift可以自动推断出您想使用大于号的字符串函数实现: reverse = names.sort( < ) print("升序:\(reverse)") 7、尾随闭包 如果您需要将一个很长的闭包表达式作为最后一个参数传递给函数,可以使用尾随闭包来增强函数的可读性。 尾随闭包是一个书写在函数括号之后的闭包表达式,函数支持将其作为最后一个参数调用。 func someFunctionThatTakesAClosure(closure: () -> ()) { // 函数体部分 closure() } //以下是不使用尾随闭包进行函数调用 someFunctionThatTakesAClosure({ //闭包主体部分 print("first:closure闭包函数被调用了") }) //以下是使用尾随闭包进行函数调用 someFunctionThatTakesAClosure { //闭包主体部分 print("second:closure闭包函数被调用了") } 注意: 如果函数只需要闭包表达式一个参数,当您使用尾随闭包时,您甚至可以把()省略掉。 例如:reverse = names.sort({ $0 > $1 }) 当闭包非常长以至于不能在一行中进行书写时,尾随闭包变得非常有用。 举例来说,Swift 的Array类型有一个map方法,其获取一个闭包表达式作为其唯一参数。 数组中的每一个元素调用一次该闭包函数,并返回该元素所映射的值(也可以是不同类型的值)。 具体的映射方式和返回值类型由闭包来指定。 当提供给数组闭包函数后,map方法将返回一个新的数组,数组中包含了与原数组一一对应的映射后的值。 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] func printOutput() -> Void { let strings = numbers.map { (var number) -> String in var output = "" while number > 0 { output = digitNames[number % 10]! + output number /= 10 } return output } print(strings) } printOutput() 8、捕获值 闭包可以在其定义的上下文中捕获常量或变量。 即使定义这些常量和变量的原域已经不存在,闭包仍然可以在闭包函数体内引用和修改这些值。 Swift最简单的闭包形式是嵌套函数,也就是定义在其他函数的函数体内的函数。 嵌套函数可以捕获其外部函数所有的参数以及定义的常量和变量。 func makeIncrementor(forIncrement amount: Int) -> () -> Int{ var runningTotal = 0 func incrementor() -> Int{ runningTotal += amount return runningTotal } return incrementor } 注意: Swift 会决定捕获引用还是拷贝值。 您不需要标注amount或者runningTotal来声明在嵌入的incrementor函数中的使用方式。 Swift 同时也处理runingTotal变量的内存管理操作,如果不再被incrementor函数使用,则会被清除。 let incrementByTen = makeIncrementor(forIncrement: 10) print(incrementByTen()) print(incrementByTen()) print(incrementByTen()) 三、打印结果:降序:["Ewa", "Daniella", "Chris", "Barry", "Alex"] 升序:["Alex", "Barry", "Chris", "Daniella", "Ewa"] 降序:["Ewa", "Daniella", "Chris", "Barry", "Alex"] 升序:["Alex", "Barry", "Chris", "Daniella", "Ewa"] 降序:["Ewa", "Daniella", "Chris", "Barry", "Alex"] 升序:["Alex", "Barry", "Chris", "Daniella", "Ewa"] first:closure闭包函数被调用了 second:closure闭包函数被调用了 ["OneSix", "FiveEight", "FiveOneZero"] 10 20 30
|
请发表评论