在Rust中如何利用现有特性实现近似GADTs的能力?
用Rust类型系统模拟GADTs核心能力
截至2023年,Rust尚未官方支持GADTs(广义代数数据类型)。我想了解,借助trait、类型成员等工具,能实现多少GADTs的核心能力。
需求场景定义
我认为「趋近GADTs」的具体场景包括:
- 条件禁用
enum构造函数 - 仅为特定
enum构造函数强制trait约束 - 解构
enum时获知其约束及构造函数
其中「条件禁用」的含义是:
- 当满足特定条件时,类型检查器会忽略某个构造函数
- 模式匹配中跳过该构造函数不会触发报错
期望行为示例
enum AlmostGADT<T> where /* magic? */ { Flexi, NotSoFlexi( /* something here maybe? */) : AlmostGADT< /* or here? */ > } fn main() { let x: AlmostGADT<condition_true!()> = AlmostGADT::NotSoFlexi(...); // 正常编译 match x { AlmostGADT::Flexi => todo!() } // 模式匹配不完整,报错 let y: AlmostGADT<condition_false!()> = AlmostGADT::NotSoFlexi(...); // 类型错误,编译失败 let y: AlmostGADT<condition_false!()> = AlmostGADT::Flexi(...); // 正常编译 match y { AlmostGADT::Flexi => todo!(), // 正常编译 AlmostGADT::NotSoFlexi(_) => todo!() // 类型错误,编译失败 } match y { AlmostGADT::Flexi => todo!() } // 正常编译,模式匹配完整 }
当前实现尝试
我目前能实现的最接近方式是携带不可能存在的值:
enum AlmostGADT<T> { Flexi, NotSoFlexi(T) } enum Void {} fn main() { let full: AlmostGADT<()> = todo!(); let partial: AlmostGADT<Void> = todo!(); }
由于无法创建Void类型的值,因此AlmostGADT<Void>的NotSoFlexi(_)构造函数也无法实例化。但遗憾的是,类型检查器不会考虑这一点——因为仍能生成该类型的表达式(比如todo!()),所以模式匹配中仍需处理这个不可能的分支,不得不使用unreachable!()来污染代码。
问题
在不同场景下该如何实现近似GADTs的功能?
我知道问题范围较广,这是因为我对Rust类型系统的了解有限。如果认为问题过宽,可参考我的AlmostGADT示例,但不必局限于此。我对实现方式没有特殊要求,可使用奇特的trait模式、nightly/实验特性、生命周期技巧等,只想了解Rust类型系统能被拓展到何种程度以实现近似GADTs的功能。
内容的提问来源于stack exchange,提问作者radrow
相关产品推荐
相关产品推荐

