令人信服Swift,由于抛出异常,函数永远不会返回

exi*_*all 13 compilation abstract throw control-flow swift

因为Swift没有抽象方法,所以我创建了一个方法,其默认实现无条件地引发错误.这会强制任何子类重写抽象方法.我的代码看起来像这样:

class SuperClass {
    func shouldBeOverridden() -> ReturnType {
        let exception = NSException(
            name: "Not implemented!",
            reason: "A concrete subclass did not provide its own implementation of shouldBeOverridden()",
            userInfo: nil
        )
        exception.raise()
    }
}
Run Code Online (Sandbox Code Playgroud)

问题:因为函数需要返回一个值,并且上面的函数没有return语句,编译失败. 我需要一些方法来说服编译器这个函数永远不会完成执行,因为它总会引发错误.

如果所有的错误处理看起来都是库级的,那么在Swift中怎么做呢?因此超出了对编译器的理解?是否有任何语言级功能(希望优雅地)终止程序的执行?

exi*_*all 24

Swift的@noreturn属性将函数和方法标记为不返回其调用者.

可能是最简单的例子,内置函数的签名abort()是:

@noreturn func abort()
Run Code Online (Sandbox Code Playgroud)

这为编译器提供了所需的所有信息.例如,以下将编译得很好:

func alwaysFail() -> Int {
    abort()
}
Run Code Online (Sandbox Code Playgroud)

虽然alwaysFail()理论上返回了一个Int,但Swift知道在abort()调用后执行不能继续.

我的原始代码不起作用的原因是因为NSException.raise是一个pre-Swift方法,因此没有该@noreturn属性.为了轻松解决这个问题,我可以使用abort():

func shouldBeOverridden() -> ReturnType {
    println("Subclass has not implemented abstract method `shouldBeOverridden`!")
    abort()
}
Run Code Online (Sandbox Code Playgroud)

或者,如果我仍想使用NSException,我可以使用适当的属性定义扩展名

extension NSException {
    @noreturn func noReturnRaise() {
        self.raise()
        abort() // This will never run, but Swift will complain that the function isn't really @noreturn if I don't call a @noreturn function before execution finishes.
    }
}
Run Code Online (Sandbox Code Playgroud)

作为第三种选择,我可以使用一个永不调用的abort()后来NSException.raise()安抚编译器.使用an的早期选项extension实际上只是这样做的抽象:

func shouldBeOverridden() -> ReturnType {
    let exception = NSException(
        name: "Not implemented!",
        reason: "A concrete subclass did not provide its own implementation of shouldBeOverridden()",
        userInfo: nil
    )
    exception.raise()
    abort() // never called
}
Run Code Online (Sandbox Code Playgroud)


Luk*_*uke 9

在Xcode 8 beta 6(Swift 3 beta 6)中,您现在可以使用Never返回类型而不是@noreturn指示函数不会返回其调用者:

func crash() -> Never {
    fatalError("Oops")
}
Run Code Online (Sandbox Code Playgroud)