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

时间:2015-01-07 21:40:32

标签: swift compilation abstract throw control-flow

因为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()
    }
}

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

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

4 个答案:

答案 0 :(得分:24)

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

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

@noreturn func abort()

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

func alwaysFail() -> Int {
    abort()
}

虽然alwaysFail()理论上返回Int,但Swift知道在abort()被调用后执行无法继续。

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

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

或者,如果我仍想使用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.
    }
}

作为第三种选择,我可以在abort()之后使用一个永不调用的NSException.raise()来安抚编译器。使用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
}

答案 1 :(得分:9)

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

func crash() -> Never {
    fatalError("Oops")
}

答案 2 :(得分:2)

通过创建协议并使shouldBeOverridden成为必需的方法,然后使您的类符合该协议,听起来您正在做的事情会更好。 https://developer.apple.com/library/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Protocols.html

答案 3 :(得分:0)

如何创建一个返回名为from ast import literal_eval mystr = """{ "key A":[ ["some val", "value a1"], ["some val", "value a2"], ["some val", "value an"] ], "key B":[ ["some val", "value b1"], ["some val", "value b2"], ], "key X":[ ["some val", "value x1"], ["some val", "value x2"], ] }""" res = {k: list(list(zip(*v))[1]) for k, v in literal_eval(mystr).items()} # {'key A': ['value a1', 'value a2', 'value an'], # 'key B': ['value b1', 'value b2'], # 'key X': ['value x1', 'value x2']} Never或类似abstract的{​​{1}}的计算属性,如下所示:

overrideMe

使用示例:

   var abstract: Never { fatalError("Must be overridden") }