FAQ:为什么可变类型不是不可变类型的子类型
来源: crumbles.blog — 2026-09-17
概述
文章回答语言论坛上的老问题:为什么可变与不可变版本的数据结构不能互为子类型。作者回到 Liskov 替换原则的严格定义,用最简单的 pair 结构推导:需要可变 pair 的地方会调用 set-car!、set-cdr!,而不可变 pair 没有这些操作,所以不可变不能顶替可变;反过来也不能,因为子类型的契约还要满足调用方对「已构造值不会被改写」的预期。
核心要点
- 关键前提是 Liskov 替换原则:S 是 T 的子类型,意味着 S 的值可以用在任何期望 T 的上下文里。
- 这个定义里的「任何」是字面意义上的任何,不是「大多数」;支持子类型的静态类型系统必须为程序证明这一点。
- 不可变 pair 无法顶替可变 pair,因为 set-car! 与 set-cdr! 在它上面根本没有定义,类型检查会直接报错。
- 反向直觉看似成立(可变 pair 提供不可变的全部操作),但类型检查的保证不只是「能调用哪些操作」。
- 作者引用 Denis Defreyne 的说法:学会不可变的那一刻,一切都变了。
金句
这不是做不到,而是这样做在形式上不正确,你至少会丢掉语言本来能给出的部分类型检查保证。
👍 0
👎 0
返回 Lobsters 首页