Swift:为什么需要“@escaping”?
Swift: why is `@escaping` needed?
我的意思是,如果编译器强制添加符号,那么在我看来它已经理解它是一个转义块。
那为什么要强制程序员加上呢?
丹克斯
它是您函数 public API 的一部分。从非转义闭包更改为转义闭包是一项重大更改。
注释的存在是为了明确这一点。
这是一个重大更改的示例:
func f(_ closure: /* @escaping */ () -> Void) {
closure()
}
struct AStruct {
var i = 0
mutating func mutate() {
f { i += 1 }
}
}
如果f
采用非转义闭包,一切都很好。但是如果你做到 @escaping
,你会得到 error: escaping closure captures mutating 'self' parameter
。
还有一些其他可能的错误与闭包捕获相关,这些错误能够有效地将结构变成引用类型(从而破坏任何来自值类型的保证)
您需要 @escaping
来区分闭包类型,因为:
并非所有闭包都是“escaping”(当然,我们对异步方法使用转义模式,但对于函数式编程模式,闭包通常是非转义的);和
编译器可以对非转义闭包进行某些优化(例如,它如何处理幕后的内存调用),而转义闭包则不可能。
最重要的是,@escaping
限定符是让编译器知道它可以进行哪些优化所必需的。
此外,我们应该始终能够查看接口并轻松推断出闭包是否正在转义。如果没有一些限定符,就很难推理一个人的代码。
FWIW,因为非转义闭包不会引入与转义闭包相同的强引用循环风险,与转义闭包相比,编译器允许对非转义闭包中的属性进行更自然的引用。通过 including/excluding @escaping
限定符,编译器还知道如何处理闭包内的 self
引用。
在遥远的过去,闭包默认为转义,我们不得不用 @noescape
注释非转义的闭包。然后,作为 SE-0103 的结果,闭包的默认值更改为非转义,从而弃用了旧的 @noescape
注释,但要求我们使用 @escaping
.[=19 注释转义闭包=]
我的意思是,如果编译器强制添加符号,那么在我看来它已经理解它是一个转义块。
那为什么要强制程序员加上呢?
丹克斯
它是您函数 public API 的一部分。从非转义闭包更改为转义闭包是一项重大更改。
注释的存在是为了明确这一点。
这是一个重大更改的示例:
func f(_ closure: /* @escaping */ () -> Void) {
closure()
}
struct AStruct {
var i = 0
mutating func mutate() {
f { i += 1 }
}
}
如果f
采用非转义闭包,一切都很好。但是如果你做到 @escaping
,你会得到 error: escaping closure captures mutating 'self' parameter
。
还有一些其他可能的错误与闭包捕获相关,这些错误能够有效地将结构变成引用类型(从而破坏任何来自值类型的保证)
您需要 @escaping
来区分闭包类型,因为:
并非所有闭包都是“escaping”(当然,我们对异步方法使用转义模式,但对于函数式编程模式,闭包通常是非转义的);和
编译器可以对非转义闭包进行某些优化(例如,它如何处理幕后的内存调用),而转义闭包则不可能。
最重要的是,@escaping
限定符是让编译器知道它可以进行哪些优化所必需的。
此外,我们应该始终能够查看接口并轻松推断出闭包是否正在转义。如果没有一些限定符,就很难推理一个人的代码。
FWIW,因为非转义闭包不会引入与转义闭包相同的强引用循环风险,与转义闭包相比,编译器允许对非转义闭包中的属性进行更自然的引用。通过 including/excluding @escaping
限定符,编译器还知道如何处理闭包内的 self
引用。
在遥远的过去,闭包默认为转义,我们不得不用 @noescape
注释非转义的闭包。然后,作为 SE-0103 的结果,闭包的默认值更改为非转义,从而弃用了旧的 @noescape
注释,但要求我们使用 @escaping
.[=19 注释转义闭包=]