Rust 的 `!` 是空类型而非底类型:没有子类型,就没法把嵌套的 never 到处强转
来源: ettolrach.com — 2026-09-08
概述
Rust 最近稳定了 never 类型 `!`,很多人习惯拿它类比类型论里的 bottom(底类型),但这篇文章论证了一个更准确的区分:`!` 其实是空类型(empty type)。两者的差异在于机制——空类型没有值也没有构造子,靠一个 `absurd : ∀A. 0→A` 消除规则任意转成别的类型;底类型同样无值无构造子,却是通过子类型让它可以顶替一切类型。只有语言具备子类型关系时二者才重合,而 Rust 的子类型只存在于带生命周期的类型之间,所以它没有底类型、只有空类型。真正反直觉的后果是:当 `!` 嵌在其他类型里(比如函数类型 `fn()->!` 或 `Result`)时,强转并不会自动发生,必须先在局部把那个 never 值解出来才能完成转换——这在 Scala 靠 subtyping 一行搞定,在 Rust 却要手写一个匹配。文章还调侃误区源头在维基百科对 empty/bottom 两页「含糊其辞」的表述,并以 Haskell 的惰性空类型 `Void` 作旁证说明严格求值下的差异。
核心要点
- `!` 没有值也没有构造子,靠 absurd 消除规则被用于任何需要的类型
- 底类型靠子类型成为一切类型的子类,而 Rust 只在带生命周期类型间有子类型
- `fn(i32)->!` 无法自动强转为 `fn(i32)->i32`,因为嵌在函数类型里就不触发强转
- 把嵌套的 never 值先解到局部变量再返回,就能与 Scala 达到同等表达力
- 误区源头或指维基百科对空类型与底类型两页的表述含糊
- Haskell 惰性的 `Void` 能不被求值地存在,说明严格求值与惰性求值在此分道扬镳
金句
the two types are not the same, and Rust does not have a bottom type — but that doesn't mean Rust isn't as expressive.
👍 0
👎 0
返回 Lobsters 首页