Swift:闭包是否引用常量或变量?

2023-11-24

我知道有几个相关的问题,而且我可以在互联网上找到很多帖子。 但是,我无法理解闭包可以保存引用的事实。对于引用类型,这是完全常见且非常合理的,但是对于值类型(包括struct and enum? 请参阅此代码。

let counter: () -> Int
var count = 0
do  {
    counter = {
        count += 1
        return count
    }
}
count += 1 // 1
counter() // 2
counter() // 3

我们可以访问值类型count通过两种方式。一种是通过使用count直接,另一个是通过闭包counter。 但是,如果我们写

let a = 0
let b = a

,记忆中b当然有不同的区域a因为它们是值类型。这种行为是值类型与引用类型不同的显着特征。 然后回到闭包主题,闭包具有对值类型的变量或常量的引用。

那么,我可以说,在闭包捕获值的情况下,值类型的特性(我们不能有任何对值类型的引用)会发生变化吗? 对我来说,捕获对值类型的引用是非常令人惊讶的,同时我上面展示的经验也表明了这一点。

你能解释一下这件事吗?


我认为造成混乱的原因是对值类型与引用类型的思考过于深入。这与此关系不大。让我们将 number 设为引用类型:

class RefInt: CustomStringConvertible {
    let value: Int
    init(value: Int) { self.value = value }
    var description: String { return "\(value)" }
}

let counter: () -> RefInt
var count = RefInt(value: 0)
do  {
    counter = {
        count = RefInt(value: count.value + 1)
        return count
    }
}
count = RefInt(value: count.value + 1) // 1
counter() // 2
counter() // 3

这感觉有什么不同吗?我希望不是。道理是一样的,只是参考文献而已。这不是一个价值/参考的东西。

关键是,正如您所注意到的,闭包捕获了变量。不是变量的值,也不是变量指向的引用的值,而是变量本身)。因此,在捕获该变量(包括调用者)的所有其他地方都可以看到闭包内变量的更改。这在中进行了更全面的讨论捕捉价值观.

如果您感兴趣的话,可以更深入一些(现在我正在讨论一些可能超出您现在关心的技术细节):

闭包实际上有对变量的引用,并且它们所做的更改立即发生,包括调用didSet等。这与inout参数,仅当它们返回时才将值分配给其原始上下文。你可以这样看:

let counter: () -> Int
var count = 0 {
    didSet { print("set count") }
}

do  {
    counter = {
        count += 1
        print("incremented count")
        return count
    }
}

func increaseCount(count: inout Int) {
    count += 1
    print("increased Count")
}

print("1")
count += 1 // 1
print("2")
counter() // 2
print("3")
counter() // 3

increaseCount(count: &count)

这打印:

1
set count
2
set count
incremented count
3
set count
incremented count
increased Count
set count

请注意“设置计数”始终位于“增量计数”之前但位于“增量计数”之后。这让我们明白闭包实际上引用的是它们捕获的同一个变量(不是值或引用;变量),以及为什么我们称其为闭包的“捕获”,而不是“传递”到函数。 (当然,您也可以“传递”到闭包,在这种情况下,它们的行为与这些参数上的函数完全相同。)

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Swift:闭包是否引用常量或变量? 的相关文章

随机推荐