繁体   English   中英

将非转义值转换为 '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关键字operation: label,如

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时,它说您将闭包转换为Any

许多检查应用于闭包类型的参数,以确保非转义闭包不会转义(关于闭包“转义”的含义,请阅读此内容):

var c: (() -> Void)?
func f(operation:() -> Void) {
    c = operation // compiler can detect that operation escapes here, and produces an error
}

但是,这些检查仅适用于闭包类型。 如果将闭包强制转换为Any ,则该闭包会丢失其闭包类型,并且编译器无法检查它是否转义。 假设编译器允许您将非转义闭包转换为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($0)
    }
    operation()
}

将闭包转换为它自己的类型也会使闭包逃逸。 这是因为operation as () -> Void是一个“相当复杂”的表达式,产生类型() -> Void “相当复杂”我的意思是它足够复杂,以至于在将其传递给非转义参数时,编译器不会费心检查您正在投射的内容是否真的是非转义的,因此它假定所有类型转换都在转义.

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM