什么是永不归类?

Sar*_*ith 25 types swift

什么是一个func与返回类型Never呢?

例如:

func addNums() -> Never {

    //my code

}
Run Code Online (Sandbox Code Playgroud)

如果我Void像这样保留返回类型会有什么区别?

func addNums() -> Void {

    //my code

}
Run Code Online (Sandbox Code Playgroud)

假设我想处理fatalError(如dpassage所说); 以下代码就足够了:

print("its an error")
return
Run Code Online (Sandbox Code Playgroud)

Apple文档说:

不正常返回的函数的返回类型,即没有值的类型.

资料来源:开发商

这不是一个重复的问题,在Swift何时以及如何使用@noreturn属性?,我希望得到更详细的答案,需要以下细节:

  1. 关于两者NeverVoid返回类型之间差异的实际例子

  2. 我们应该采用这些回报类型的条件.

  3. 返回类型也有可能为零; 我也需要对这个功能进行比较

答案应该集中在差异上.

Hex*_*ire 26

Never返回类型是在Swift 3中引入的替换@noreturn键.

请参阅此提案中的理由:
SE-0102删除@noreturn属性并引入空的Never类型

正如官方文件所述:

返回类型的函数不能正常返回; 没有值的类型.

在声明无条件抛出错误,陷阱或以其他方式终止的闭包,函数或方法时,使用Never作为返回类型.

资料来源:https://developer.apple.com/documentation/swift/never

基本插图:

// The following function is our custom function we would use
// to manually and purposefully trigger crash. In the logs,
// we can specify what exactly went wrong: e.g. couldn't cast something, 
// couldn't call something or some value doesn't exist:
func crashApp() -> Never {
    fatalError("Something very, very bad happened! Crash the app!")
}
Run Code Online (Sandbox Code Playgroud)

Erica Sadun@noreturn引用的用法细节和优势:

  • 永远不允许函数或方法抛出:eg()throws - > Never.抛出允许用于错误修复的辅助路径,即使在预期不会返回的函数中也是如此.
  • 作为第一类类型,永远不会以@noreturn属性不能的方式使用泛型.
  • 切勿主动阻止功能同时声明返回类型和不返回.这是旧系统下的潜在问题.

第一个注意事项(关于二次错误修复)可能特别重要.Never函数可以有复杂的逻辑和抛出 - 不一定崩溃.

让我们来看看一些有趣的用例之间的比较NeverVoid

决不

例1

func noReturn() -> Never {
    fatalError() // fatalError also returns Never, so no need to `return`
}

func pickPositiveNumber(below limit: Int) -> Int {
    guard limit >= 1 else {
        noReturn()
        // No need to exit guarded scope after noReturn
    }
    return rand(limit)
}
Run Code Online (Sandbox Code Playgroud)

例2

func foo() {
    abort()
    print("Should not reach here") // Warning for this line
}
Run Code Online (Sandbox Code Playgroud)

例3

func bar() -> Int {
    if true {
        abort() // No warning and no compiler error, because abort() terminates it.
    } else {
        return 1
    }
}
Run Code Online (Sandbox Code Playgroud)

abort() 定义为:

public func abort() -> Never
Run Code Online (Sandbox Code Playgroud)

空虚

返回时,这些例子是不可能的Void:

public func abortVoid() -> Void {
    fatalError()
}

func bar() -> Int {
    if true {
        abortVoid() // ERROR: Missing return in a function expected to return 'Int'
    } else {
        return 1
    }
}
Run Code Online (Sandbox Code Playgroud)

abort()回来收拾它Never:

func bar() -> Int {
    if true {
        abort() // No ERROR, but compiler sees it returns Never and warns:
        return 2 // Will never be executed
    } else {
        return 1
    }
}
Run Code Online (Sandbox Code Playgroud)

我们Void用来告诉编译器没有返回值.应用程序继续运行

我们用Never告诉编译器没有返回调用者站点.应用程序runloop终止.


小智 8

空虚

Void本身就是一个返回类型,它是一个零元素的元组.您可以互换使用Void和().

看看这些例子,

  1. func yourFunc() {} 这是一个没有返回类型的函数,它基本上返回一个零元素的元组,可以写成()

  2. func yourFunc() -> Void {} 显式通知编译器返回void类型的函数

  3. func yourFunc() -> () {} 此返回类型()显示与void类型相同.()表示元素为零的元组

决不

从不返回类型通知编译器不需要返回空元组().此外,具有永不返回类型的函数用于当前执行的退出点,如崩溃,致命错误,中止或退出.

有关never的详细了解,让我们看一下abort()示例:

1.

 func yourFunc() {
    abort()
    print("Will not reach at this point") //Warning for this line
} 
Run Code Online (Sandbox Code Playgroud)

2.

 func yourFunc() -> Int {
    if true {
        abort()
    } else {
        return 1
    }
}
Run Code Online (Sandbox Code Playgroud)

从上面的代码片段中,我们可以看到何时调用abort()(它不返回值)作为函数中的最后一个语句,该函数需要返回一个值(在我们的例子中是Int).编译器不会生成警告.

中止()

public func abort() -> Never
Run Code Online (Sandbox Code Playgroud)

类似于exit():

public func exit(_: Int32) -> Never
Run Code Online (Sandbox Code Playgroud)

Apple文档说:" 在声明无条件抛出错误,陷阱或以其他方式终止的闭包,函数或方法时,使用Never作为返回类型. "

因此,如果您想编写一个记录灾难性错误的自定义函数,您应该使用返回类型Never来向编译器发出信号:

func catastrophicErrorDisplay(error: String) -> Never {
    DisplaySomeCustomLogFacility(error)
}
Run Code Online (Sandbox Code Playgroud)

简而言之," 永远不会用于突然和完全失败,从而无法恢复. "


dpa*_*age 5

Never表示函数永远不会返回。它旨在用于fatalError导致程序故意崩溃的事情,通常是在记录错误之后。您可能不应该使用它,除非您正在为应用程序中的灾难性错误制作处理程序。

这与不返回值的函数不同,如您的第二个代码段。你也可以把它写成func addNums() -> Void.


Aht*_*hti 5

为了更好地理解Neverand Void,以及如何Never在比旧的更多的上下文中有用@noreturn,让我们首先看看这两种类型的实际定义是什么:


Never这里定义为:

public enum Never {}
Run Code Online (Sandbox Code Playgroud)

由于无法实例化空枚举的值,因此类型系统保证不Never存在任何实例。这意味着指定其返回类型的函数Never被类型系统阻止在任何情况下实际返回。

编译器在进行控制流分析时会考虑到这一点。例如,这两个函数都编译没有错误,而如果一个返回的函数Void被替换为,它们就会失败fatalError

func foo(fail: Bool) -> String {
    if fail {
        fatalError()
    } else {
        return "foo"
    }
    // notice there is no return statement here
}

func bar(fail: Bool) -> Void {
    let s: String
    if fail {
        fatalError()
        // the compiler doesn't complain s is not initialized here
    } else {
        s = "bar"
    }
    print(s)
}
Run Code Online (Sandbox Code Playgroud)

Void这里定义为:

public typealias Void = ()
Run Code Online (Sandbox Code Playgroud)

空元组没有两个不同的实例。因此,返回的函数的返回值Void不包含任何信息。

您实际上可以编写return ()return Void()。您还可以使用返回的“值”,如下所示:

func empty() -> Void {}
let v = empty()
print(type(of: v)) // prints "()"
Run Code Online (Sandbox Code Playgroud)

尽管编译器会警告“常量 'v' 推断为具有类型 'Void',这可能是意外的”。


根据类型系统而不是特殊语言特性来定义NeverVoid使我们能够用泛型做一些非常聪明的事情。让我们看一个Result类型的例子,它是成功和失败类型的泛型。

enum Result<R, E> {
    case success(R)
    case failure(E)
}
Run Code Online (Sandbox Code Playgroud)

一个可能的专业化是Result<Void, MyError>. 这意味着您的结果在成功时不包含除成功之外的任何信息。

另一种可能是Result<String, Never>。编译器保证这个结果永远不会是失败的情况。

自选互动Never,并Void以类似的方式。Never?只能永远为零,并且Void?只保存信息是否为零,仅此而已(它基本上是一个更复杂的布尔值)。这两者本身都不是很有用,但可能会出现在NeverVoid在某处用作通用参数时。


在实践中,您很少会编写返回Never. 我个人使用它来包装fatalError创建一个函数,用于标记尚未实现的函数:

func unimplemented(f: String = #function) -> Never {
    fatalError("\(f) is not implemented yet")
}
Run Code Online (Sandbox Code Playgroud)

函数返回的另一个示例NeverdispatchMain(),它可以在命令行实用程序中用于启动DispatchQueue.main. 由于此队列随后等待新块,因此dispatchMain()永远不会返回。