使用const函数计算泛型常量时遭遇无约束泛型常量错误
问题场景
在Rust类型级编程中遇到unconstrained generic constant错误,最小复现代码如下:
#![feature(generic_const_exprs)] const fn func1<T, U>() -> bool { true } // 自定义逻辑 const fn func2<T, U>() -> bool { false } // 自定义逻辑 // 提供布尔常量的访问接口 trait CompareResult { const R1: bool; const R2: bool; } struct CompareResultHolder<const R1: bool, const R2: bool>(); impl<const R1: bool, const R2: bool> CompareResult for CompareResultHolder<R1, R2> { const R1: bool = R1; const R2: bool = R2; } trait CompareTypeList { type Compare<T>: CompareResult; } impl<T> CompareTypeList for T { type Compare<U> = CompareResultHolder<{func1::<T, U>()}, {func2::<T, U>()}>; }
预期通过<<T as CompareTypeList>::Compare<U> as CompareResult>::R1访问计算出的常量值,但编译器报错unconstrained generic constant,给出的提示也无法直接解决问题:help: try adding a wherebound using this expression:where [(); {func2::<T, U>()}]:``。
错误原因
这个错误的核心在于Rust编译器无法确保func1::<T, U>()和func2::<T, U>()的计算结果是唯一确定的——哪怕你的func1和func2逻辑固定,从编译器角度看,泛型参数T和U可以是任意类型,它无法提前验证所有T/U组合下这两个const fn的返回值不会产生歧义,也无法确保后续代码不会出现改变这些常量值的冲突实现。
另外,当前generic_const_exprs特性仍处于nightly阶段,类型检查逻辑还不完善,对于关联类型中直接使用泛型常量表达式的场景,编译器无法正确推导常量的约束条件,导致误报“无约束”错误。
解决方法
我们可以给关联类型添加where约束,明确告诉编译器泛型常量的计算结果合法且唯一。这里可以利用Rust将布尔值转换为数组长度的特性(true对应1,false对应0),通过要求数组类型合法来“锚定”常量值:
#![feature(generic_const_exprs)] const fn func1<T, U>() -> bool { true } // 自定义逻辑 const fn func2<T, U>() -> bool { false } // 自定义逻辑 trait CompareResult { const R1: bool; const R2: bool; } struct CompareResultHolder<const R1: bool, const R2: bool>(); impl<const R1: bool, const R2: bool> CompareResult for CompareResultHolder<R1, R2> { const R1: bool = R1; const R2: bool = R2; } trait CompareTypeList { type Compare<U>: CompareResult; } impl<T> CompareTypeList for T { type Compare<U> = CompareResultHolder<{func1::<T, U>()}, {func2::<T, U>()}> where [(); {func1::<T, U>()}]:, [(); {func2::<T, U>()}]:; }
修改后,你就能正常使用<<T as CompareTypeList>::Compare<U> as CompareResult>::R1访问目标常量值了。
内容的提问来源于stack exchange,提问作者LucioleMaléfique

