Swift 学习笔记(闭包)

谈到函数式编程,恐怕最不能放过的就是闭包。闭包的定义总是不那么清晰,好像每种语言都有小许的差别。通常说的是可以捕获(访问)外部变量语句块,Swift 的闭包类似于 Objective-C 的 Block 或其他语言的 Lambda 表达式。所以闭包同 Lambda 基本上是同义词。

现在还没完, Swift 认为全局函数(有名字的,不能捕获外部变量)和嵌套函数(有名字,可捕获外部变量)也认为是特殊的闭包。闭包表达式(无名字的闭)才是真正意义上的闭包,它用最简洁的方式来书写一个函数。因此它尽了最大的可能的作了约定性的简化,例如参数与返回类型的推断,return 的省略,无参或只有一个参数的简化。

闭包的语法形式

   { (parameters) -> return type in
        statements
    }

闭包中可用常量参数(let),变量参数(var), inout 参数,甚至是可变个数参数,但是不能用默认参数。说白了,闭包也就是无名函数的另一种写法。

在 Java8 中为了保持兼容性,所以设计出了 SAM(Single Abstract Method),让 Java8 的 Lambda 表达式与含有 SAM 的类型进行 1:1 映射。在 Swift 可无须这般,它直接就是在某处接受一个函数,那么符合格式(参数到返回值的)函数就可以放到这里来,你也可以写成闭包形式。回到 Objective-C 可以想像是要求一个 Selector 或是一个 Block,也就是匹配类型就是。

譬如说数组排序时可以接受函数类型参数是

Swift-closure-1

(String, String) -> Bool

那么我们可以定义一个函数传给它,或者定义成一个闭包传过去,以及逐步的不讲道理的简化方式

*闭包中,只有一条语时才能省去 return 关键字

尾闭包(Trailing Closure)

如果闭包是作为函数的最后一个参数,那么它可以单独甩在外面,在圆括号;而如果闭包是作为函数的唯一个参数,那么除适用前一原则外,还允许把圆括号也省去,分别是

这种简化法在闭包体比较长时很有意义,{} 里表明了这是一个操作块。比如上面的 op 函数第三个参数接受的闭包写了三行,假装它比较复杂一些。

闭包捕获外部变量

Swift 的闭包捕获外部常,变量的特性与 Javascript 是一样的,在这点上是比 Java 8 要灵活

@noescape 闭包

如果传入函数中的闭包在函数返回前就完成了调用,那么这个闭包就是 @noescape 的,意味着不能逃离函数而存在。如果传入函数的闭包在函数返回后还想调用它,那就不是一个 @noescape 的了,强型加 @noescape 注解就要报编译错误的,例如

withEscapingClosure() 中强型给 closure 加上 @noescape 编译时会报

Invalid conversion from non-escaping function of type '@noescape () -> Void'

那么 @noescape 有什么作用呢?它可以使用该中隐式的访问 self 的变量。

参考:Closures

 

本文链接 https://yanbin.blog/swift-learning-closues/, 来自 隔叶黄莺 Yanbin Blog

[版权声明] Creative Commons License 本文采用 署名-非商业性使用-相同方式共享 4.0 国际 (CC BY-NC-SA 4.0) 进行许可。

Subscribe
Notify of
guest

0 Comments
Inline Feedbacks
View all comments