7-13.【高级特性】Never 类型在泛型和控制流中有什么作用?

8 阅读2分钟

Never 是 Swift 中一个非常特殊的存在,它被称为 "Bottom Type"(底类型) 。它的定义非常简单,但也非常霸道:它是一个没有成员的枚举(Empty Enum)

这意味着你永远无法实例化一个 Never 类型的值。正是这种“无法存在”的特性,让它在控制流和泛型中发挥了巨大的逻辑作用。


1. 在控制流中的作用:告知编译器“此路不通”

Never 出现之前,执行必死无疑的操作(如 fatalError)返回的是 Void。但 Void 实际上是有值的(即 ()),这会让编译器认为函数执行完后还会继续往下走。

而返回 Never 的函数被称为 Non-returning Function(永不返回的函数)

优化逻辑分支

如果你在 guard 语句或 switch 中调用了一个返回 Never 的函数,编译器知道程序在此处会终止,因此不需要你在后面写 returnbreak

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 的规则:

  1. 枚举是值类型。
  2. 一个没有 case 的枚举无法被初始化
  3. 因此,任何声明为 Never 的变量都无法被赋予真实的值。

这在类型论中非常完美:Any 是类型的顶峰(包含所有),Never 是底端(不包含任何)。


4. 总结对比

场景使用 Never 的效果
函数返回告知编译器该点之后的代码不可达(Unreachable),消除多余的 return
泛型约束逻辑上消除某种状态(如“绝不报错”或“没有数据”)。
协议实现如果某个协议要求一个关联类型,而你当前的实现不需要它,可以用 Never 填充。