[英]Converting non-escaping value to 'Any' may allow it to escape error - within not escaping function
My question is derived from the following Japanese question.我的问题来自以下日本问题。 It's not my question, but I'm trying to answer the following problem but I cannot find the suitable answer.
这不是我的问题,但我正在尝试回答以下问题,但我找不到合适的答案。
https://teratail.com/questions/298998 https://teratail.com/questions/298998
The question above will be simpled like below.上面的问题会像下面一样简单。
func executetwice(operation:() -> Void) {
print(operation)
operation()
}
This compiler required to add @escaping
keyword after operation:
label, such as这个编译器要求在
operation:
后加上@escaping
关键字operation:
label,如
func executetwice(operation: @escaping () -> Void) {
print(operation)
operation()
}
But in fact, it seems that operation
block does not escape from this block.但实际上,似乎
operation
块并没有从这个块中逃脱。
Another way,其它的办法,
func executetwice(operation:() -> Void) {
let f = operation as Any
operation()
}
also compiler requires to add @escaping
keyword.编译器还需要添加
@escaping
关键字。 It is just upcasting to Any
.它只是向上转换
Any
。 In other case, just casting to same type, it seems to be error.在其他情况下,只是强制转换为相同的类型,似乎是错误的。
func executetwice(operation:() -> Void) {
let f = operation as () -> Void //Converting non-escaping value to '() -> Void' may allow it to escape
operation()
}
I'm not sure why I need to add @escaping
keyword with no escaping condition.我不确定为什么我需要添加没有转义条件的
@escaping
关键字。
Just adding @escaping
keyword will be Ok, but I would like to know why the compiler required the keyword in this case.只需添加
@escaping
关键字就可以了,但我想知道为什么编译器在这种情况下需要关键字。
print
accepts (a variable number of) Any
as arguments, so that is why it's saying that you are converting a closure to Any
when you pass it to print
. print
接受(可变数量的) Any
作为参数,所以这就是为什么当您将闭包传递给print
时,它说您将闭包转换为Any
。
Many checks are applied on closure-typed parameters to make sure a non-escaping closure don't escape (for what it means for a closure to "escape", read this ):许多检查应用于闭包类型的参数,以确保非转义闭包不会转义(关于闭包“转义”的含义,请阅读此内容):
var c: (() -> Void)?
func f(operation:() -> Void) {
c = operation // compiler can detect that operation escapes here, and produces an error
}
However, these checks are only applied on closure types.但是,这些检查仅适用于闭包类型。 If you cast a closure to
Any
, the closure loses its closure type, and the compiler can't check for whether it escapes or not.如果将闭包强制转换为
Any
,则该闭包会丢失其闭包类型,并且编译器无法检查它是否转义。 Let's suppose the compiler allowed you to cast a non-escaping closure to Any
, and you passed it to g
below:假设编译器允许您将非转义闭包转换为
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
}
Therefore, the compiler is designed to be conservative and treats "casting to Any
" as "making a closure escape".因此,编译器被设计为保守的并将“强制转换为
Any
”视为“进行闭包逃逸”。
But we are sure that print
doesn't escape the closure, so we can use withoutActuallyEscaping
:但是我们确信
print
不会逃脱闭包,所以我们可以使用withoutActuallyEscaping
:
func executetwice(operation:() -> Void) {
withoutActuallyEscaping(operation) {
print($0)
}
operation()
}
Casting a closure to its own type also makes the closure escape.将闭包转换为它自己的类型也会使闭包逃逸。 This is because
operation as () -> Void
is a "rather complex" expression producing a value of type () -> Void
.这是因为
operation as () -> Void
是一个“相当复杂”的表达式,产生类型() -> Void
。 And by "rather complex" I mean it is complex enough that when passing that to a non-escaping parameter, the compiler doesn't bother to check whether what you are casting really is non-escaping, so it assumes that all casts are escaping. “相当复杂”我的意思是它足够复杂,以至于在将其传递给非转义参数时,编译器不会费心检查您正在投射的内容是否真的是非转义的,因此它假定所有类型转换都在转义.
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.