10

else我在流的上下文中阅读了关键字后用花括号括起来的代码块guard-else,必须调用标有noreturn属性或转移控制的函数return或使用、break或。continuethrow

最后一部分很清楚,而我不太了解第一部分。

首先,任何函数都会返回一些东西(至少是一个空元组),即使你没有声明任何返回类型。其次,我们什么时候可以使用noreturn函数?建议某些核心内置方法的文档是否标有noreturn

保护语句的 else 子句是必需的,并且必须调用一个标有 noreturn 属性的函数,或者使用以下语句之一将程序控制转移到保护语句的封闭范围之外:

return

break

continue

throw

这里是来源

4

3 回答 3

14

首先,任何函数都会返回一些东西(至少是一个空元组),即使你没有声明任何返回类型。

(@noreturn 已过时;请参阅下面的 Swift 3 更新。)不,有些函数会立即终止进程并且返回给调用者。这些在 Swift 中用 标记@noreturn,例如

@noreturn public func fatalError(@autoclosure message: () -> String = default, file: StaticString = #file, line: UInt = #line)
@noreturn public func preconditionFailure(@autoclosure message: () -> String = default, file: StaticString = #file, line: UInt = #line)
@noreturn public func abort()
@noreturn public func exit(_: Int32)

可能还有更多。

备注:类似的注解存在于其他编程语言或编译器中,例如[[noreturn]]在 C++11 中,__attribute__((noreturn))作为 GCC 扩展,或_Noreturn用于 Clang 编译器。)

如果它也无条件@noreturn终止进程,您可以标记您自己的函数,例如通过调用内置函数之一,例如

@noreturn func myFatalError() {
    // Do something else and then ...
    fatalError("Something went wrong!")
}

现在您可以在语句的 else 子句中使用您的函数guard

guard let n = Int("1234") else { myFatalError() }

@noreturn函数还可用于标记“不应发生”的情况并指示编程错误。一个简单的例子(来自Missing return UITableViewCell的摘录):

override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
    let cell: MyTableViewCell

    switch (indexPath.row) {
    case 0:
        cell = tableView.dequeueReusableCellWithIdentifier("cell0", forIndexPath: indexPath) as! MyTableViewCell
        cell.backgroundColor = UIColor.greenColor()
    case 1:
        cell = tableView.dequeueReusableCellWithIdentifier("cell1", forIndexPath: indexPath) as! MyTableViewCell
        cell.backgroundColor = UIColor.redColor()
    default:
        myFatalError()
    }
    // Setup other cell properties ...
    return cell
}

如果没有myFatalError()标记为@noreturn,编译器会抱怨默认情况下缺少返回。


更新:在 Swift 3 (Xcode 8 beta 6) 中,该@noreturn属性已被替换为Never返回类型,因此上面的示例现在可以写成

func myFatalError() -> Never  {
    // Do something else and then ...
    fatalError("Something went wrong!")
}
于 2016-06-29T11:55:17.043 回答
1

简单的游乐场,看看它是如何工作的......

//: Playground - noun: a place where people can play

import Foundation
@noreturn func foo() {
    print("foo")
    exit(1)
}

var i: Int?

guard let i = i else {
    foo()
}

print("after foo") // this line will never executed

//prints foo and finish
于 2016-06-29T12:28:31.063 回答
0

例如,考虑在结果类型中返回值或错误的异步操作。我们通常这样写。

enum Result<Value, Error> {
    case success(Value)
    case failure(Error)
}

func fetch(_ request: URLRequest,
          completion: (Result<(URLResponse, Data), Error>) -> Void) {
    // ...
}

现在,如果你知道一个总是返回值,从不出错的函数,那么我们可以这样写:

func alwaysSucceeds(_ completion: (Result<String, Never>) -> Void) {
    completion(.success("yes!"))
}

当编译器看到Never时,它不会强迫您将所有 switch 案例写得详尽,因此您可以跳过 .failure 如下。

alwaysSucceeds { (result) in
    switch result {
    case .success(let string):
        print(string)
    }
}

参考:https ://nshipster.com/never/

于 2019-04-08T08:24:03.657 回答