为什么Swift全局函数作为闭包的特例捕获全局变量?

时间:2018-03-12 16:23:21

标签: ios swift closures

根据Apple Swift documentation:全局函数是具有名称且捕获任何值的闭包。但是我在本书 IOS 11编程基础与Swift 中讨论了使用闭包的示例,它将全局函数A作为参数传递给另一个全局函数B进行修改全局变量x的值。该书指出A捕获X,这与Swift文档所说的相矛盾。

代码示例:

func pass100(_ f: (Int) -> ()) {
    f(100)
}

var x = 0
print(x) // output 0

func setX(newX: Int) {
     x = newX
}

pass100(setX)
print(x) //output 100

上面的代码片段在Xcode中工作,我很困惑。谁能解释一下这里发生了什么?

2 个答案:

答案 0 :(得分:5)

This是“捕获”的意思:

  

闭包可以从定义它的周围上下文中捕获常量和变量。然后闭包可以引用并修改其体内的常量和变量的值,即使定义常量和变量的原始范围不再存在。

据说全局函数没有捕获任何东西,因为在程序运行时你永远不会离开全局范围,因此捕获任何东西都没有意义。如果它确实捕获了某些东西,那意味着即使在你以某种方式“离开”全局范围(可能程序完成运行)之后,全局变量仍然可以改变,这很奇怪。

代码中的全局函数没有捕获任何内容。它可以更改x的值,因为x仍在范围内。你没有离开全球范围。

答案 1 :(得分:0)

  

闭包可以从周围捕获常量和变量   定义它的上下文。

全球化,就像本地一样,是一种背景。 A是一个全局函数,X是一个全局变量;因此,A会抓住X。从技术上讲,应用程序中的所有方法都捕获X,因为它在全局上下文中公开。然而,按照惯例,“捕获”通常指的是局部范围。

为了证明这一点,如果您将AX移动到本地范围(例如类中的方法),则没有任何更改 - A仍会捕获X。您在示例中所做的全部工作都放在全局范围内,并且因为它们处于相同的范围(或上下文)中,所以捕获规则没有改变。

这是语义和惯例的问题,我认为这是一个Swift文档可能会有些误导的领域(如果我是Apple,我会改写它)。将函数从本地范围移动到全局范围绝不会改变其捕获能力。我认为Apple的意思是默认情况下,本地方法总是捕获一些东西(即使它是self),而如果没有任何东西可以被捕获,则不保证全局函数捕获任何东西。