理解闭包——捕获值

Understanding closures - capturing values

在 Swift 编程语言文档中,闭包,“捕获值”有以下示例:

func makeIncrementer(forIncrement amount: Int) -> () -> Int {
    var runningTotal = 0
    func incrementer() -> Int {
        runningTotal += amount
        return runningTotal
    }
    return incrementer
}

除了第一次调用 makeIncrementer 时 runningTotal 仅初始化为 0 之外,我遵循了描述。该文档显示以下内容:

let incrementByTen = makeIncrementer(forIncrement: 10)
incrementByTen()
// returns a value of 10
incrementByTen()
// returns a value of 20
incrementByTen()
// returns a value of 30

为什么每次调用 incrementByTen 时 runningTotal 都不重置为 0?

查看return值:

makeIncrementerreturnsincrementer,内函数,amountrunningTotal被捕获,runningTotal设置一次。

这是一个很好的关于范围的课程,因为它正在捕获。在原始示例中,runningTotalincrementer() 的范围之外,并且 incrementer() 已捕获此值。如果将 runningTotal 放在 incrementer() 内,更改其范围,每次调用时输出都会重置为 0,因为 runningTotal 现在是局部范围的,它的值不会在外部持续存在函数——这里没有捕获任何内容。

func makeIncrementer(forIncrement amount: Int) -> () -> Int {
    func incrementer() -> Int {
        var runningTotal = 0 // local
        runningTotal += amount
        return runningTotal
    }
    return incrementer
}

let incrementByTen = makeIncrementer(forIncrement: 10)
incrementByTen() // 10
incrementByTen() // 10
incrementByTen() // 10

假设 runningTotal 是一个全局变量,在所有内容之外声明。现在应该清楚为什么每次调用该函数时都不会重置该值。但是对于incrementer(),这个作用域和原来的例子没有区别。在这两种情况下,runningTotal 都是它捕获的函数范围之外的变量。

var runningTotal = 0 // global

func makeIncrementer(forIncrement amount: Int) -> () -> Int {
    func incrementer() -> Int {
        runningTotal += amount
        return runningTotal
    }
    return incrementer
}

let incrementByTen = makeIncrementer(forIncrement: 10)
incrementByTen() // 10
incrementByTen() // 20
incrementByTen() // 30