将非转义值转换为 'Any' 可能允许它转义错误 - 在不转义函数内
Converting non-escaping value to 'Any' may allow it to escape error - within not escaping function
我的问题来源于下面的日文问题。
这不是我的问题,但我正在尝试回答以下问题,但找不到合适的答案。
https://teratail.com/questions/298998
上面的问题会像下面这样简单化。
func executetwice(operation:() -> Void) {
print(operation)
operation()
}
此编译器要求在operation:
标签后添加@escaping
关键字,如
func executetwice(operation: @escaping () -> Void) {
print(operation)
operation()
}
但实际上operation
块似乎并没有从这个块中逃脱。
另一种方式,
func executetwice(operation:() -> Void) {
let f = operation as Any
operation()
}
编译器还需要添加 @escaping
关键字。它只是向上转换为 Any
。
在其他情况下,只是转换为相同的类型,它似乎是错误的。
func executetwice(operation:() -> Void) {
let f = operation as () -> Void //Converting non-escaping value to '() -> Void' may allow it to escape
operation()
}
我不确定为什么我需要添加没有转义条件的 @escaping
关键字。
只需添加 @escaping
关键字即可,但我想知道为什么编译器在这种情况下需要关键字。
print
接受(可变数量的)Any
作为参数,所以这就是为什么当你将闭包传递给 print
.
对 closure-typed 参数应用了许多检查以确保 non-escaping 闭包不会逃逸(对于闭包“逃逸”的含义,阅读 ) :
var c: (() -> Void)?
func f(operation:() -> Void) {
c = operation // compiler can detect that operation escapes here, and produces an error
}
但是,这些检查仅适用于闭包类型。如果将闭包强制转换为 Any
,则闭包会丢失其闭包类型,并且编译器无法检查它是否转义。假设编译器允许您将 non-escaping 闭包强制转换为 Any
,并将其传递给下面的 g
:
var c: Any?
func g(operation: Any) {
// the compiler doesn't know that "operation" is a closure!
// You have successfully made a non-escaping closure escape!
c = operation
}
因此,编译器设计得比较保守,将“转换为 Any
”视为“进行闭包转义”。
但是我们确定print
不会逃脱闭包,所以我们可以使用withoutActuallyEscaping
:
func executetwice(operation:() -> Void) {
withoutActuallyEscaping(operation) {
print([=12=])
}
operation()
}
将闭包转换为它自己的类型也会使闭包转义。这是因为 operation as () -> Void
是一个“相当复杂”的表达式,它产生一个 () -> Void
类型的值。我所说的“相当复杂”是指它足够复杂,以至于在将其传递给 non-escaping 参数时,编译器不会费心检查您正在转换的内容是否真的是 non-escaping,因此它假设所有演员都在逃跑。
我的问题来源于下面的日文问题。 这不是我的问题,但我正在尝试回答以下问题,但找不到合适的答案。
https://teratail.com/questions/298998
上面的问题会像下面这样简单化。
func executetwice(operation:() -> Void) {
print(operation)
operation()
}
此编译器要求在operation:
标签后添加@escaping
关键字,如
func executetwice(operation: @escaping () -> Void) {
print(operation)
operation()
}
但实际上operation
块似乎并没有从这个块中逃脱。
另一种方式,
func executetwice(operation:() -> Void) {
let f = operation as Any
operation()
}
编译器还需要添加 @escaping
关键字。它只是向上转换为 Any
。
在其他情况下,只是转换为相同的类型,它似乎是错误的。
func executetwice(operation:() -> Void) {
let f = operation as () -> Void //Converting non-escaping value to '() -> Void' may allow it to escape
operation()
}
我不确定为什么我需要添加没有转义条件的 @escaping
关键字。
只需添加 @escaping
关键字即可,但我想知道为什么编译器在这种情况下需要关键字。
print
接受(可变数量的)Any
作为参数,所以这就是为什么当你将闭包传递给 print
.
对 closure-typed 参数应用了许多检查以确保 non-escaping 闭包不会逃逸(对于闭包“逃逸”的含义,阅读
var c: (() -> Void)?
func f(operation:() -> Void) {
c = operation // compiler can detect that operation escapes here, and produces an error
}
但是,这些检查仅适用于闭包类型。如果将闭包强制转换为 Any
,则闭包会丢失其闭包类型,并且编译器无法检查它是否转义。假设编译器允许您将 non-escaping 闭包强制转换为 Any
,并将其传递给下面的 g
:
var c: Any?
func g(operation: Any) {
// the compiler doesn't know that "operation" is a closure!
// You have successfully made a non-escaping closure escape!
c = operation
}
因此,编译器设计得比较保守,将“转换为 Any
”视为“进行闭包转义”。
但是我们确定print
不会逃脱闭包,所以我们可以使用withoutActuallyEscaping
:
func executetwice(operation:() -> Void) {
withoutActuallyEscaping(operation) {
print([=12=])
}
operation()
}
将闭包转换为它自己的类型也会使闭包转义。这是因为 operation as () -> Void
是一个“相当复杂”的表达式,它产生一个 () -> Void
类型的值。我所说的“相当复杂”是指它足够复杂,以至于在将其传递给 non-escaping 参数时,编译器不会费心检查您正在转换的内容是否真的是 non-escaping,因此它假设所有演员都在逃跑。