[英]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: ,我希望得到更详细的答案,需要以下细节:
Practical examples on the difference between both Never
and Void
as return types 关于Never
和Void
作为返回类型之间差异的实际示例
Condition by which we should adopt these return types. 我们应该采用这些回报类型的条件。
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引用:
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
让我们看一些有趣的用例以及Never
和Void
之间的比较
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
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, 看看这些例子,
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() {}
这是一个没有返回类型的函数,它基本上返回一个零元素的元组,可以写成()
func yourFunc() -> Void {}
Function which is explicitly informing the compiler about return type of void func yourFunc() -> Void {}
显式通知编译器返回void类型的函数
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: 为了更好地理解Never
和Void
,以及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. 根据类型系统而不是特殊语言特性来定义Never
和Void
使我们能够使用泛型做一些非常聪明的事情。 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以类似的方式与Never
和Void
交互。 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. 这些都不是非常有用,但是当Never
或Void
在某处被用作通用参数时可能会出现。
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.