定义上,闭包是实现词法作用域的一种手段。在 Python、JavaScript 中都有闭包。简单来说,闭包就是一个保留了其定义时环境变量的函数,即使该环境已经不复存在。变量作为自由变量存在于函数内,就像被函数捕获了一样(参见Python 中的闭包与局部作用域)。

通常会把一个在局部定义的函数成为闭包。

Swift 中的闭包也不例外,它是自包含的函数代码块,可以在代码中被传递和使用,闭包可以捕获和存储其所在上下文中任意常量和变量的引用。

Swift 中有三种形式的闭包:

全局函数:一个有名字但不捕获任何值的闭包。

嵌套函数:一个有名字且可以捕获其封闭函数域内值的闭包。

闭包表达式:一个轻量级的可以捕获其上下文变量及常量的匿名闭包。

全局函数和嵌套函数闭包在 JavaScript 等语言内也是很常见的,在此我们就不再做进一步的研究,这里我们主要研究的是第三中形式:闭包表达式。

我们定义了一个闭包作为 by 参数的值。

闭包表达式可以有以下几个更简洁的形式:

如果需要将一个闭包表达式作为一个函数的最后一个参数,而这个闭包表达式又很长,可以使用尾随闭包来增加可读性。尾随闭包写在函数括号后,即使它是函数的一个参数。

可以看到其构造器最后一个参数接收一个返回 Content 类型的闭包,所以文章开头提到的代码其实就是尾随闭包。

如果尾随闭包是函数的唯一参数,则函数括号也可以省略:

捕获值是闭包最基础的性质。利用这一性质,我们可以方便的写出一些高阶函数。

这是因为函数和闭包是引用类型。当我们把闭包赋值给一个常量或者变量时,指向闭包的 increOne 是常量或者变量,而非闭包的内容。

如果一个闭包作为参数传递给函数,但是在函数返回之后才执行,就称这个闭包从函数中逃逸。我们可以在参数名前添加 @escaping 来标注允许这个闭包逃逸。

如果一个闭包不接收任何参数,调用时返回闭包内的表达式,我们可以添加 @autoclosure 来将表达式自身作为闭包。

自动闭包可以省略花括号,但是过度使用会降低代码的可读性。

本站文字由LiYan创作,采用知识共享署名 4.0 国际许可协议进行许可。