什么是 Never 返回类型?
Posted
技术标签:
【中文标题】什么是 Never 返回类型?【英文标题】:What is the Never return type? 【发布时间】:2018-04-04 18:56:18 【问题描述】:返回类型为Never
的func
有什么作用?
例如:
func addNums() -> Never
//my code
如果我将返回类型保持为Void
这样会有什么不同?
func addNums() -> Void
//my code
假设我希望处理fatalError
(如dpassage 所说);下面的代码就足够了:
print("its an error")
return
Apple 文档说:
不正常返回的函数的返回类型,即没有值的类型。
来源:Developer
这不是When and how to use @noreturn attribute in Swift? 的重复问题,因为我希望得到更详细的答案,需要以下详细信息:
关于Never
和Void
作为返回类型的区别的实例
我们应该采用这些返回类型的条件。
返回类型也有可能为 nil;我也需要比较该功能
答案应该集中在差异上。
【问题讨论】:
见这个例如***.com/questions/38098608/… Swift Evolution/0102 "Apple 对 Never 类型的解释是未明确指定返回类型的函数的返回类型" – 不,不是,来自Void
文档。
@Saranjith 实际使用很简单。为答案添加了示例,没有不必要的复杂性。
【参考方案1】:
Never
表示函数永远不会返回。它旨在用于像fatalError
这样导致您的程序故意崩溃的事情,通常是在记录错误之后。你可能不应该使用它,除非你正在做一些事情,比如为你的应用程序中的灾难性错误创建一个处理程序。
这与不返回值的函数不同,如第二个 sn-p。你也可以写成func addNums() -> Void
。
【讨论】:
【参考方案2】:Never
在 Swift 3 中引入了返回类型来替换 @noreturn
键。
请参阅此提案中的理由:SE-0102 Remove @noreturn attribute and introduce an empty Never type
正如官方文档解释的那样:
不正常返回的函数的返回类型;一种类型 没有值。
在声明闭包时使用 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!")
@noreturn
的使用细节和优势,由 Erica Sadun 引用:
第一个注意事项(关于二级错误修复)可能特别重要。 Never
函数可以有复杂的逻辑并抛出 - 不一定会崩溃。
让我们看看Never
和Void
之间的一些有趣的用例和比较
从不
示例 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)
示例 2
func foo()
abort()
print("Should not reach here") // Warning for this line
示例 3
func bar() -> Int
if true
abort() // No warning and no compiler error, because abort() terminates it.
else
return 1
abort()
定义为:
public func abort() -> Never
无效
如果它返回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
然后用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
我们使用 Void
告诉编译器有没有返回值。应用程序继续运行。
我们使用 Never
告诉编译器没有返回调用者站点。应用程序运行循环已终止。
【讨论】:
【参考方案3】:为了更好地理解Never
和Void
,以及Never
如何在比旧的@noreturn
更多的上下文中有用,让我们首先看看这两种类型的实际定义是什么:
Never
定义为 here:
public enum Never
由于无法实例化空枚举的值,类型系统保证不存在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)
Void
定义为 here:
public typealias Void = ()
空元组没有两个不同的实例。因此,返回Void
的函数的返回值不包含任何信息。
您实际上可以写return ()
或return Void()
。您也可以使用返回的“值”,如下所示:
func empty() -> Void
let v = empty()
print(type(of: v)) // prints "()"
尽管编译器会警告“Constant 'v' inferred to have type 'Void', which may be unexpected”。
根据类型系统而不是特殊的语言特性来定义Never
和Void
使我们能够用泛型做一些非常聪明的事情。让我们看一个 Result
类型的示例,它对成功和失败类型都是通用的。
enum Result<R, E>
case success(R)
case failure(E)
可能的特化是Result<Void, MyError>
。这意味着您有一个结果,在成功时,除了它成功的事实之外不包含任何信息。
另一种可能是Result<String, Never>
。编译器保证这个结果永远不会失败。
Optional 以类似的方式与 Never
和 Void
交互。 Never?
只能是 nil,Void?
只保存它是否为 nil 的信息,仅此而已(它基本上是一个更复杂的 Bool)。这两者本身并不是很有用,但当Never
或Void
在某处用作泛型参数时可能会出现。
实际上,您很少会编写返回Never
的函数。我个人用它来包装fatalError
来创建一个我用来标记尚未实现的函数的函数:
func unimplemented(f: String = #function) -> Never
fatalError("\(f) is not implemented yet")
另一个返回Never
的函数示例是dispatchMain()
,它可以在命令行实用程序中用于启动DispatchQueue.main
。由于这个队列会等待新的块,dispatchMain()
永远不会返回。
【讨论】:
【参考方案4】:无效
Void 本身就是一个返回类型,它是一个零元素的元组。您可以交替使用 Void 和 ()。
看看这些例子,
func yourFunc()
这是一个没有返回类型的函数,基本上返回一个零元素的元组,可以写成()
func yourFunc() -> Void
显式通知编译器返回类型为 void 的函数
func yourFunc() -> ()
这个()的返回类型显示和void类型一样。 () 表示零元素的元组
从不
Never return-type 通知编译器不需要返回空元组 ()。此外,具有永不返回类型的函数用于当前执行的退出点,例如崩溃、致命错误、中止或退出。
为了详细了解never,我们来看一个 abort() 示例:
1.
func yourFunc()
abort()
print("Will not reach at this point") //Warning for this line
2.
func yourFunc() -> Int
if true
abort()
else
return 1
从上面的代码 sn-ps 中,我们可以看到 当我们调用 abort()(它不返回值)作为函数中期望返回值的最后一条语句(在我们的例子中诠释)。编译器不会生成警告。
中止()
public func abort() -> Never
exit() 类似:
public func exit(_: Int32) -> Never
苹果文档说:“在声明无条件抛出错误、陷阱或不终止的闭包、函数或方法时,使用 Never 作为返回类型。”
因此,如果您想编写一个记录灾难性错误的自定义函数,您应该使用返回类型 Never 向编译器发出信号:
func catastrophicErrorDisplay(error: String) -> Never
DisplaySomeCustomLogFacility(error)
简而言之,“从不用于无法恢复的突然且完全的故障。”
【讨论】:
以上是关于什么是 Never 返回类型?的主要内容,如果未能解决你的问题,请参考以下文章
PHPPHP 8.1 的新特性一览 | 交叉类型枚举never 返回类型Fibers 纤程readonly 只读属性