Swift:闭包是否引用了常量或变量? [英] Swift: Does closure have references to constants or variables?

查看:105
本文介绍了Swift:闭包是否引用了常量或变量?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I know there are several related question and moreover I can find many posts in the Internet. However, I can't understand the fact that closures can hold references. In case of a reference type, it is totally usual and very reasonable, but how about a value type, including struct and enum? See this code.

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

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

We can access the value type count through two ways. One is by using count directly and the another is through the closure counter. However, if we write

let a = 0
let b = a

在内存中, b 当然具有与 a ,因为它们是值类型。这种行为是值类型的一个明显特征,与引用类型不同。
然后回到闭包主题,闭包引用值类型的变量或常量。

, in the memory b has of course a different area with a because they are value type. And this behavior is a distinct feature of value type which is different with reference type. And then backing to the closure topic, closure has the reference to value type's variable or constant.

那么,我可以说值类型的功能是在闭包捕获值的情况下我们无法对值类型进行任何引用吗?
对我来说,捕获对值类型的引用非常令人惊讶,同时我上面显示的经验也表明了这一点。

So, can I say the value type's feature that we can't have any references to value type is changed in case of closure's capturing values? To me, capturing references to value type is very surprising and at the same time the experience I showed above indicates that.

您能解释一下这件事吗?

Could you explain this thing?

推荐答案

我认为造成混淆的原因是对值类型与引用类型的思考过于刻板。这与此无关。让我们以数字作为引用类型:

I think the confusion is by thinking too hard about value types vs reference types. This has very little to do with that. Let's make number be reference types:

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

这感觉有什么不同吗?我希望不是。是相同的,只是参考。这不是值/参考值。

Does this feel different in any way? I hope not. It's the same thing, just in references. This isn't a value/reference thing.

关键是,正如您所注意到的,闭包捕获变量。不是变量的值,也不是变量指向的引用的值,而是变量本身。因此,在捕获该变量的所有其他位置(包括调用方),都可以看到对闭包内部变量的更改。在捕获值

The point is that, as you note, the closure captures the variable. Not the value of the variable, or the value of the reference the variable points to, but the variable itself). So changes to the variable inside the closure are seen in all other places that have captured that variable (including the caller). This is discussed a bit more fully in Capturing Values.

如果您有兴趣的话,请加深了解(现在我要讲一点技巧)

A bit deeper if you're interested (now I'm getting into a bit of technicalities that may be beyond what you care about right now):

闭包实际上是对该变量的引用,并且它们会立即发生更改,包括调用 didSet 等。这与 inout 参数不同,后者仅在返回时将值分配给其原始上下文。您可以看到这种方式:

Closures actually have a reference to the variable, and changes they make immediately occur, including calling didSet, etc. This is not the same as inout parameters, which assign the value to their original context only when they return. You can see that this way:

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

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

Note how "set count" is always before "incremented count" but is after "increased count." This drives home that closures really are referring to the same variable (not value or reference; variable) that they captured, and why we call it "capturing" for closures, as opposed to "passing" to functions. (You can also "pass" to closures of course, in which case they behave exactly like functions on those parameters.)

这篇关于Swift:闭包是否引用了常量或变量?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆