另一个闭包内的闭包是逃逸或非逃逸

问题描述 投票:0回答:1
func perform(_ clsr: () -> Void) {
    let anotherClosure = {
        clsr()
    }
}

上面的代码被编译,但是当将

anotherClosure
更改为
var
时,编译器给出错误:

转义闭包捕获非转义参数'clsr'

func perform(_ clsr: () -> Void) {
    var anotherClosure = { // error: Escaping closure captures non-escaping parameter 'clsr'
        clsr()
    }
}

还有

func perform(_ clsr: () -> Void) {
    // now it's let still I get the error
    let anotherClosure = {
        clsr()
    }
    
    anotherClosure() // error: Escaping closure captures non-escaping parameter 'clsr'
}

但是

func perform(_ clsr: () -> Void) {
 
    let anotherClosure = {
        clsr()
    }
    
    anotherPerfom(anotherClosure) // Now it's works fine
}

func anotherPerfom(_ clsr: () -> Void){
  clsr()
}

幕后发生了什么?谁能给我解释一下吗?

swift closures
1个回答
0
投票

须知:

  • 转义意味着函数被“存储”在某个地方以供以后执行。如果要存储函数参数is以供以后执行,则其函数类型必须标记为@escaping

    
    

  • 这里的闭包就是一个匿名函数体。闭包有能力“捕获”函数外部定义的值。这种捕获是一种存储形式(这是使闭包变得非常酷和有用的一部分)。
  • 好的,我们开始吧。

func perform(_ clsr: () -> Void) { let anotherClosure = { clsr() } }

这会初始化一个不可变值,
anotherClosure
,而无需任何后续引用。因此,从编译器的角度来看,这几乎就像 
perform

没有内容一样。您会收到一条警告,指出您有一个未引用的

let
,但仅此而已;编译器不需要考虑
anotherClosure
content
,因为 anotherClosure 将被优化掉。

func perform(_ clsr: () -> Void) {
    var anotherClosure = {
        clsr()
    }
}

和以前一样,但现在
let
var

。这意味着

anotherClosure
不会被优化掉;这次是“真实的”。因此
anotherClosure
是通过
storing
在其中初始化一个闭包,该闭包使用其闭包
capturing
功能来引用(从而捕获)clsr 参数。 因此,您所做的正是错误消息所说的:
anotherClosure
正在使用转义闭包(大括号)进行初始化,该闭包捕获

clsr

,这是一个非转义参数(因为您没有说

@escaping
) 。要解决这个问题,你会说
func perform(_ clsr: @escaping () -> Void) {

func perform(_ clsr: () -> Void) { let anotherClosure = { clsr() } anotherClosure() }
这就像第一个,带有 
let
,但现在 
is

是对

anotherClosure
的后续引用,因此 anotherClosure 无法被优化掉。但这意味着情况与第二个(带有
var
的那个)完全相同;编译器必须考虑
anotherClosure
如何
存储
一个闭包(花括号),它
捕获
传入参数clsr,并且它得出与前面的示例完全相同的结论,完全相同原因。
最后但并非最不重要的一点:

func perform(_ clsr: () -> Void) { let anotherClosure = { clsr() } anotherPerform(anotherClosure) } func anotherPerform(_ clsr: () -> Void) { clsr() }

这个例子就像第一个例子一样——这是一个可以优化的

let
。如果你说
var

,我们就会回到第二个例子,但你没有。和你说的一模一样

func perform(_ clsr: () -> Void) {
    anotherPerform({ clsr() })
}

func anotherPerform(_ clsr: () -> Void) {
    clsr()
}
这样写,我们可以看到,事实上,任何一个 

clsr
 值都没有发生 
存储;第一个

clsr 函数会立即执行。因此,没有任何内容被转义,并且函数类型不必声明为 @escaping

© www.soinside.com 2019 - 2024. All rights reserved.