闭包是独立的功能块,可以在代码中传递和使用。<code>Swift</code> 中的闭包类似于 <code>C</code> 和 <code>Objective-C</code> 中的 <code>Block</code> 以及其他编程语言中的 <code>lambda</code>(匿名函数)。 闭包可以从定义它们的上下文中捕获和存储对任何常量和变量的引用。这称为关闭这些常量和变量。<code>Swift</code> 为您处理所有捕获的内存管理。
以上是Swift 官方对闭包的概述。闭包是引用类型,与函数一样。无论何时将函数或闭包赋值给常量或变量,实际上都是将该常量或变量设置为对函数或闭包的引用。
在Functions 中介绍的全局和嵌套函数实际上是闭包的特殊情况。闭包采用以下三种形式之一:
全局函数是具有名称且不捕获任何值的闭包。
嵌套函数是具有名称并且可以从其封闭函数中捕获值的闭包。
闭包表达式是用轻量级语法编写的未命名闭包,可以从其周围的上下文中捕获值。
<code>Swift</code> 的闭包表达式具有干净、清晰的风格,其优化并鼓励在常见场景中使用简洁、整洁的语法。这些优化包括:
从上下文推断参数和返回值类型
单表达式闭包的隐式返回
简写参数名称
尾随闭包语法
闭包表达式语法具有以下一般形式,这跟很多高级编程语言的闭包写法类似:
Swift 的标准库提供了一个名为 的方法<code>sorted(by:)</code>,我们通过改方法简单了解一下闭包的使用吧。
闭包作为函数参数进行传递,但是该闭包并未在函数返回前调用,而是在函数返回后才被调用,则这个闭包被称为逃逸闭包。当我们声明一个以闭包作为参数之一的函数时,我们可以在该闭包参数的类型之前书写<code>@escaping</code>来表示该闭包允许逃逸。
举个使用场景,当一个函数需要用到异步操作回调的时候需要使用逃逸闭包。 实现闭包逃逸的一种途径是通过将该闭包存储到定义在函数外面的变量中,稍后再去调用。
<code>autoclosure</code>是一个被自动创建的闭包,用于包装作为参数传递给函数的表达式。该表达式被自动创建为:不含参数,返回值省略(根据表达式的返回值决定)<code>in</code>关键字省略,方法体中只含表达式的闭包。
当该函数被调用时,自动闭包会返回表达式的值。我们可以通过在函数类型前使用关键字<code>@autoclosure</code>把自动闭包外围的花括号<code>{}</code>都给去掉。但是重点是使用<code>@autoclosure</code>关键字只限于修饰参数中的闭包,并且该闭包的类型可以有返回值,但绝对不能有参数。
使用关键字<code>@autoclosure</code>标记闭包参数为自动闭包类型的。调用函数时,传递闭包的实参时,可以像传<code>String</code>类型的参数一样而不是闭包那样传递。
注意:过度使用<code>autoclosures</code>会使我们的代码难以理解。上下文和函数名称应该明确表示该闭包的调用被推迟了。 自动闭包同时也允许逃逸。需要同时使用<code>@autoclosure</code>和<code>@escaping</code>属性。
闭包可以从定义它的周围上下文中捕获常量和变量。闭包可以在其方法体中引用并修改常量和变量的值,即使定义常量和变量的原始作用域不存在。 在 <code>Swift</code> 中,一个闭包可以捕获值的最简单形式就是嵌套函数。一个嵌套函数可以捕获任何它外围函数的参数也可以捕获定义在外围函数里的常量和变量。
《Swift中闭包底层原理探索》
《Swift里的高阶函数》
《The Swift Programming Language》- Closures