提问人:itsAj 提问时间:8/18/2023 最后编辑:HangarRashitsAj 更新时间:8/19/2023 访问量:49
另一个闭合中的闭合是逃逸或非逃逸
Closure inside another closure is escaping or non-escaping
问:
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()
}
这背后发生了什么?谁能给我解释一下?
答:
须知事项:
转义意味着函数存储在某个地方以供以后执行。如果要存储函数参数以供以后执行,则必须将其函数类型标记为 。
@escaping
此处的闭包是一个匿名函数体。闭包能够捕获在函数外部定义的值。这种捕获是一种存储形式(这是使闭包非常酷和有用的部分原因)。
好的,我们开始吧。
案例 1
func perform(_ clsr: () -> Void) {
let anotherClosure = {
clsr()
}
}
这将初始化一个不可变值 ,而不对它进行任何后续引用。因此,从编译器的角度来看,这几乎就像是没有内容一样。您会收到一条警告,指出您有一个未引用的,但仅此而已;编译器不需要考虑 因为 的内容将被优化。anotherClosure
perform
let
anotherClosure
anotherClosure
案例 2
func perform(_ clsr: () -> Void) {
var anotherClosure = {
clsr()
}
}
和以前一样,但现在是一个.这意味着它不会被优化;这次是“真实的”。因此,通过在其中存储一个闭包来初始化,该闭包使用其闭包捕获能力来引用(并因此捕获)参数。let
var
anotherClosure
anotherClosure
clsr
因此,您正在执行错误消息所说的操作:正在使用转义闭包(大括号)进行初始化,该闭包捕获了哪些是非转义参数(因为您没有说)。要解决这个问题,你会说anotherClosure
clsr
@escaping
func perform(_ clsr: @escaping () -> Void) {
案例 3
func perform(_ clsr: () -> Void) {
let anotherClosure = {
clsr()
}
anotherClosure()
}
这就像第一个,带有 ,但现在有后续的 ,所以不能被优化掉。但这意味着情况与第二个完全相同(具有 );编译器必须考虑如何存储捕获传入参数的闭包(大括号),并且出于完全相同的原因,它得出的结论与上一个示例完全相同。let
anotherClosure
anotherClosure
var
anotherClosure
clsr
案例 4
最后但并非最不重要的一点是:
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
评论
let
var
var