简体   繁体   English

什么是永不归类?

[英]What is the Never return type?

What does a func with return type Never do? 具有返回类型的func Never不做什么?

For example: 例如:

func addNums() -> Never {

    //my code

}

What will be the difference if I kept the return type as Void like this? 如果我像这样保留返回类型为Void会有什么区别?

func addNums() -> Void {

    //my code

}

Suppose I wish to handle a fatalError (as said by dpassage ); 假设我希望处理一个fatalError (如dpassage所说 ); the below code will be sufficient: 以下代码就足够了:

print("its an error")
return

Apple documentation says: Apple文档说:

The return type of functions that do not return normally, that is, a type with no values. 不正常返回的函数的返回类型,即没有值的类型。

Source: Developer 资料来源: 开发商

This was not a duplicate question of When and how to use @noreturn attribute in Swift? 这不是一个重复的问题, 在Swift何时以及如何使用@noreturn属性? , as I wish for a more detailed answer which needs details like: ,我希望得到更详细的答案,需要以下细节:

  1. Practical examples on the difference between both Never and Void as return types 关于NeverVoid作为返回类型之间差异的实际示例

  2. Condition by which we should adopt these return types. 我们应该采用这些回报类型的条件。

  3. Also there is a chance the return type can be nil; 返回类型也有可能为零; I need a comparison of that feature too 我也需要对这个功能进行比较

The answer should focus on the differences. 答案应该集中在差异上。

Never return type was introduced in Swift 3 to substitute @noreturn key. Never在Swift 3中引入返回类型来替换@noreturn键。

See justification in this proposal: 请参阅此提案中的理由:
SE-0102 Remove @noreturn attribute and introduce an empty Never type SE-0102删除@noreturn属性并引入一个空的Never类型

As official documentation explains: 正如官方文件所述:

The return type of functions that do not return normally; 返回类型的函数不能正常返回; a type with no values. 没有值的类型。

Use Never as the return type when declaring a closure, function, or method that unconditionally throws an error, traps, or otherwise does not terminate. 在声明无条件抛出错误,陷阱或以其他方式终止的闭包,函数或方法时,使用Never作为返回类型。

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

Basic illustration: 基本插图:

// 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!")
}

Usage specifics and advantages over @noreturn , as referenced by Erica Sadun : @noreturn ,使用细节和优势,由Erica Sadun引用:

  • Never allows a function or method to throw: eg () throws -> Never. 永远不允许函数或方法抛出:eg()throws - > Never。 Throwing allows a secondary path for error remediation, even in functions that were not expected to return. 抛出允许用于错误修复的辅助路径,即使在预期不会返回的函数中也是如此。
  • As a first class type, Never works with generics in a way that the @noreturn attribute could not. 作为第一类类型,永远不会以@noreturn属性不能的方式使用泛型。
  • Never proactively prevents a function from claiming both a return type and no-return at the same time. 切勿主动阻止功能同时声明返回类型和不返回。 This was a potential issue under the old system. 这是旧系统下的潜在问题。

First note (regarding secondary error remediation) is probably particularly important. 第一个注意事项(关于二次错误修复)可能特别重要。 Never function can have complex logic and throw – not necessarily crash. Never功能可以有复杂的逻辑和抛出 - 不一定崩溃。

Let's see some interesting use cases and comparison between Never and Void 让我们看一些有趣的用例以及NeverVoid之间的比较

Never 决不

Example 1 例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)
}

Example 2 例2

func foo() {
    abort()
    print("Should not reach here") // Warning for this line
}

Example 3 例3

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

abort() is defined as: abort()定义为:

public func abort() -> Never

Void 空虚

These examples would not have been possible with it returning Void : 返回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
    }
}

And to pack it up with abort() returning Never : 并使用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
    }
}

We use Void to tell compiler there is no return value . 我们使用Void告诉编译器没有返回值 Application keeps running. 应用程序继续运行

We use Never to tell compiler there is no return to caller site . 我们使用Never告诉编译器没有返回调用者站点 Application runloop is terminated. 应用程序runloop终止。

Void 空虚

Void is itself a return type which is a tuple with zero elements. Void本身就是一个返回类型,它是一个零元素的元组。 You can use Void and () interchangeably. 您可以互换使用Void和()。

Look at these examples, 看看这些例子,

  1. func yourFunc() {} This is a function without a return type, which basically returns a tuple with zero elements, that can be written as () func yourFunc() {} 这是一个没有返回类型的函数,它基本上返回一个零元素的元组,可以写成()

  2. func yourFunc() -> Void {} Function which is explicitly informing the compiler about return type of void func yourFunc() -> Void {} 显式通知编译器返回void类型的函数

  3. func yourFunc() -> () {} This return type of () displays the same as void type. func yourFunc() -> () {} 此返回类型()显示与void类型相同。 () indicates a tuple with zero elements ()表示元素为零的元组

Never 决不

Never return-type informs the compiler that no need exists to return an empty tuple (). 从不返回类型通知编译器不需要返回空元组()。 Also, function with the never return type is used for the exit point of the current execution like a crash, fatal error, abort or exit. 此外,具有永不返回类型的函数用于当前执行的退出点,如崩溃,致命错误,中止或退出。

For a detailed understanding of never , let's have a look at an abort() example : 有关never的详细了解,让我们看一下abort()示例:

1. 1。

 func yourFunc() {
    abort()
    print("Will not reach at this point") //Warning for this line
} 

2. 2。

 func yourFunc() -> Int {
    if true {
        abort()
    } else {
        return 1
    }
}

From the above code snippets, we can see when we call abort() (which doesn't return a value) as the last statement in a function that expects a value to be returned (in our case Int). 从上面的代码片段中,我们可以看到何时调用abort()(它不返回值)作为函数中的最后一个语句,该函数需要返回一个值(在我们的例子中是Int)。 The compiler doesn't generate a warning. 编译器不会生成警告。

abort() 中止()

public func abort() -> Never

Similarly for exit(): 类似于exit():

public func exit(_: Int32) -> Never

The apple documentation says: " Use Never as the return type when declaring a closure, function, or method that unconditionally throws an error, traps, or otherwise does not terminate. " Apple文档说:“ 在声明无条件抛出错误,陷阱或以其他方式终止的闭包,函数或方法时,使用Never作为返回类型。

So if you want to write a custom function that logs a catastrophic error , you should use the return type Never to signal to the compiler: 因此,如果您想编写一个记录灾难性错误的自定义函数,您应该使用返回类型Never来向编译器发出信号:

func catastrophicErrorDisplay(error: String) -> Never {
    DisplaySomeCustomLogFacility(error)
}

In short " Never is used for sudden and total failure from which recovery is impossible. " 简而言之,“ 永远不会用于突然和完全失败,从而无法恢复。

Never indicates that the function will never return. Never表示该功能永远不会返回。 It's intended to be used for things like fatalError which cause your program to crash intentionally, often after logging an error. 它旨在用于fatalError类的fatalError ,这会导致程序故意崩溃,通常是在记录错误之后。 You probably shouldn't use it unless you're doing something like making a handler for catastrophic errors in your application. 你可能不应该使用它,除非你正在为你的应用程序中的灾难性错误做一个处理程序。

This is different from a function which just doesn't return a value, as in your second snippet. 这与不返回值的函数不同,就像在第二个代码段中一样。 You could also write that as func addNums() -> Void . 您也可以将其写为func addNums() -> Void

To better understand Never and Void , and how Never is useful in more contexts than the old @noreturn was, let's first look at what the two types actually are defined as: 为了更好地理解NeverVoid ,以及Never如何在比旧的@noreturn更多的上下文中有用,让我们首先看看这两种类型实际定义为:


Never is defined here as: 这里 Never定义为:

public enum Never {}

Since there is no way to instantiate a value of an empty enum, the type system guarantees that no instance of Never can exist. 由于无法实例化空枚举的值,因此类型系统保证不存在Never实例。 This means functions that specify their return type as Never are prevented by the type system from actually returning under any circumstances. 这意味着类型系统阻止将其返回类型指定为Never函数在任何情况下都不会实际返回。

The compiler takes this into account when doing control-flow analysis. 编译器在进行控制流分析时会考虑这一点。 For example, these two functions both compile without error, whereas they would fail if a function that returns Void was substituted for fatalError : 例如,这两个函数都编译时没有错误,但如果返回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)
}

Void is defined here as: Void 在这里定义为:

public typealias Void = ()

There are no two different instances of an empty tuple. 空元组没有两个不同的实例。 Thus, the return value of functions returning Void holds no information. 因此,返回Void的函数的返回值不包含任何信息。

You can actually write return () or return Void() . 您实际上可以编写return ()return Void() You can also use the "value" returned, like this: 您还可以使用返回的“值”,如下所示:

func empty() -> Void {}
let v = empty()
print(type(of: v)) // prints "()"

although the compiler will warn "Constant 'v' inferred to have type 'Void', which may be unexpected". 虽然编译器会警告“常量'v'推断出类型为'Void',这可能是意料之外的”。


Defining both Never and Void in terms of the type system rather than as special language features enables us to do some pretty clever things with generics. 根据类型系统而不是特殊语言特性来定义NeverVoid使我们能够使用泛型做一些非常聪明的事情。 Let's look at an example of a Result type, generic over both the success and failure type. 让我们看一下Result类型的示例,它是成功和失败类型的通用类型。

enum Result<R, E> {
    case success(R)
    case failure(E)
}

A possible specialization of this would be Result<Void, MyError> . 可能的专业化是Result<Void, MyError> This would mean you have a result that, on success, does not hold any information beyond the fact it succeeded. 这意味着您的结果是,在成功的情况下,除了成功之外不会保留任何信息。

Another possibility could be Result<String, Never> . 另一种可能是Result<String, Never> This result is guaranteed by the compiler to never be the failure case. 编译器保证这个结果永远不会失败。

Optionals interact with Never and Void in a similar way. Optionals以类似的方式与NeverVoid交互。 Never? can only ever be nil, and Void? 只能是零和Void? only holds the information wether it is nil or not, nothing more (it's basically a more complicated Bool). 只保留信息,无论是否为零,仅此而已(基本上是一个更复杂的Bool)。 Both of these are not very useful on their own, but might appear when Never or Void are used as generic parameters somewhere. 这些都不是非常有用,但是当NeverVoid在某处被用作通用参数时可能会出现。


In practice, you will rarely write functions returning Never . 在实践中,您很少会编写返回Never函数。 I have personally used it to wrap fatalError to create a function I use to mark functions that are not implemented yet: 我个人用它来包装fatalError来创建一个我用来标记尚未实现的函数的函数:

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

Another example of a function returning Never is dispatchMain() , which can be used in command-line utilities to start the DispatchQueue.main . 返回Never的函数的另一个示例是dispatchMain() ,它可以在命令行实用程序中用于启动DispatchQueue.main Since this queue then waits for new blocks, dispatchMain() never returns. 由于此队列等待新块,因此dispatchMain()永远不会返回。

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

相关问题 无法将&#39;Never&#39;类型的返回表达式转换为&#39;String&#39;类型的返回值 - Cannot convert return expression of type 'Never' to return type 'String' 什么类型返回executeFetchRequest - What type return executeFetchRequest 什么是返回类型“()”? - What is return type “ () ”? 无法转换“列表”类型的返回表达式<Never, _> &#39; 返回类型 &#39;some View&#39; - Cannot convert return expression of type 'List<Never, _>' to return type 'some View' 无法转换类型“(AnyPublisher)的返回表达式<demoobject, never> , APIError)' 返回类型 'AnyPublisher<demoobject, apierror> '</demoobject,></demoobject,> - Cannot convert return expression of type '(AnyPublisher<DemoObject, Never>, APIError)' to return type 'AnyPublisher<DemoObject, APIError>' 函数calcDecrement的返回类型中“()”的含义是什么? - What is the meaning of the “()” in the return type of function calcDecrement? swift中函数的默认返回类型是什么? - What is the default return type of a function in swift? &#39;return&#39; 之后的代码永远不会被执行 - Code after 'return' will never be executed 使用元组而不是字典作为返回类型的好处是什么? - What is the advantage of using tuple over dictionary as a return type? SwiftUI 我自己渲染的 function 的返回类型是什么? - SwiftUI what is the return-type of my own render's function?
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM