Never 是 Swift 中一个非常特殊的存在,它被称为 "Bottom Type"(底类型) 。它的定义非常简单,但也非常霸道:它是一个没有成员的枚举(Empty Enum) 。
这意味着你永远无法实例化一个 Never 类型的值。正是这种“无法存在”的特性,让它在控制流和泛型中发挥了巨大的逻辑作用。
1. 在控制流中的作用:告知编译器“此路不通”
在 Never 出现之前,执行必死无疑的操作(如 fatalError)返回的是 Void。但 Void 实际上是有值的(即 ()),这会让编译器认为函数执行完后还会继续往下走。
而返回 Never 的函数被称为 Non-returning Function(永不返回的函数) 。
优化逻辑分支
如果你在 guard 语句或 switch 中调用了一个返回 Never 的函数,编译器知道程序在此处会终止,因此不需要你在后面写 return 或 break。
Swift
func crashAndBurn() -> Never {
fatalError("程序在此处终结")
}
func test(input: Int?) {
guard let value = input else {
crashAndBurn() // 编译器知道这里不会返回,所以不需要 return
}
print(value) // 只有成功时才会执行
}
2. 在泛型中的作用:表示“不可能发生的情况”
这是 Never 最精妙的用法。它常被用作泛型占位符,用来在类型层面上关闭某种可能性。
A. Result<Success, Failure>
如果你有一个异步任务,逻辑上它永远不会失败(比如从内存读取配置),你可以这样定义:
Swift
let successOnly: Result<String, Never> = .success("Everything is fine")
因为 Failure 类型是 Never,而 Never 无法产生实例,所以你永远无法构造出一个 .failure 情况。这让处理结果时非常清爽:
Swift
switch successOnly {
case .success(let message):
print(message)
// 不需要写 case .failure,编译器知道它根本不存在
}
B. Combine 中的 Publisher
在 Combine 框架中,如果一个发布者永远不会抛出错误,它的 Failure 类型就会被设为 Never。这允许你使用 .assign(to:on:) 等要求不报错的操作符。
3. 本质:为什么它是 Empty Enum?
在 Swift 中,Never 的底层实现就是一个不带任何 case 的枚举:
Swift
public enum Never {}
根据 Swift 的规则:
- 枚举是值类型。
- 一个没有 case 的枚举无法被初始化。
- 因此,任何声明为
Never的变量都无法被赋予真实的值。
这在类型论中非常完美:Any 是类型的顶峰(包含所有),Never 是底端(不包含任何)。
4. 总结对比
| 场景 | 使用 Never 的效果 |
|---|---|
| 函数返回 | 告知编译器该点之后的代码不可达(Unreachable),消除多余的 return。 |
| 泛型约束 | 逻辑上消除某种状态(如“绝不报错”或“没有数据”)。 |
| 协议实现 | 如果某个协议要求一个关联类型,而你当前的实现不需要它,可以用 Never 填充。 |
英文版
7-13. [Advanced] What is the role of the Never type in Generics and Control Flow?
Never is a highly unique entity in Swift, known in Type Theory as the "Bottom Type." Its definition is incredibly simple yet absolute: it is an empty enumeration (an enum with no cases).
This means you can never instantiate a value of type Never. It is precisely this "impossibility of existence" that allows it to perform critical logical functions within control flow and generics.
1. Role in Control Flow: Informing the Compiler of "Dead Ends"
Before Never was introduced, operations that inevitably terminated the process (like fatalError) returned Void. However, Void actually has a value (the empty tuple ()), which leads the compiler to assume that execution could potentially continue after the function call.
A function that returns Never is known as a Non-returning Function.
Optimizing Logical Branches
If you call a function returning Never inside a guard statement or a switch case, the compiler understands that the program terminates at that point. Consequently, it does not require a return, break, or throw following that call.
Swift
func crashAndBurn() -> Never {
fatalError("The program ends here")
}
func test(input: Int?) {
guard let value = input else {
crashAndBurn() // The compiler knows this doesn't return; no 'return' needed.
}
print(value) // This only executes upon success
}
2. Role in Generics: Representing "Impossible Scenarios"
This is the most elegant application of Never. It is frequently used as a generic placeholder to logically disable a specific possibility at the type level.
A. Result<Success, Failure>
If you have an asynchronous task that, by design, can never fail (such as reading a configuration already loaded in memory), you can define it as follows:
Swift
let successOnly: Result<String, Never> = .success("Everything is fine")
Because the Failure type is Never, and Never cannot be instantiated, it is impossible to construct a .failure case. This makes handling the result much cleaner:
Swift
switch successOnly {
case .success(let message):
print(message)
// No need for a .failure case; the compiler knows it cannot exist.
}
B. Publisher in Combine
In the Combine framework, if a publisher is guaranteed never to emit an error, its Failure type is set to Never. This allows you to use operators like .assign(to:on:), which require a non-failing stream.
3. The Essence: Why an Empty Enum?
In Swift, the underlying implementation of Never is an enum with no cases:
Swift
public enum Never {}
According to Swift's rules:
- Enums are value types.
- An enum with no cases cannot be initialized.
- Therefore, no variable declared as
Nevercan ever hold an actual value.
In Type Theory, this represents a perfect hierarchy: Any is the Top Type (containing everything), and Never is the Bottom Type (containing nothing).
4. Summary Table
| Scenario | Effect of using Never |
|---|---|
| Function Return | Informs the compiler that subsequent code is unreachable, eliminating redundant return statements. |
| Generic Constraints | Logically eliminates a state (e.g., "guaranteed no error" or "no data"). |
| Protocol Implementation | If a protocol requires an associated type that your specific implementation doesn't need, use Never as a filler to disable that path. |