如何避免自定义嵌套枚举DashNumber的TryFrom实现递归溢出
问题:DashNumber枚举实现TryFrom时的递归溢出错误
尝试为自定义枚举DashNumber实现std::convert::TryFrom trait,将其转换为usize类型,但编译时出现递归溢出错误,原因是编译器尝试生成DashNumber<DashNumber<T>>等嵌套类型的转换实现。
原代码
use core::*; enum DashNumber<N> { NegInfinity, Number(N), Infinity, } #[derive(Debug)] enum TryFromDashNumberError<T: std::fmt::Debug> where usize: TryFrom<T>, <usize as TryFrom<T>>::Error: std::error::Error + 'static, { NegInfinity, Number(<usize as TryFrom<T>>::Error), Infinity, } impl<T> fmt::Display for TryFromDashNumberError<T> where usize: TryFrom<T>, <usize as TryFrom<T>>::Error: std::error::Error + 'static, T: std::fmt::Debug, { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match self { TryFromDashNumberError::<T>::NegInfinity => { write!(f, "Negative infinity cannot be converted to a usize") } TryFromDashNumberError::<T>::Number(e) => { write!(f, "Error converting number to usize: {}", e) } TryFromDashNumberError::<T>::Infinity => { write!(f, "Infinity cannot be converted to a usize") } } } } impl<T> TryFrom<DashNumber<T>> for usize where usize: TryFrom<T>, <usize as TryFrom<T>>::Error: std::error::Error + 'static, T: std::fmt::Debug, { type Error = TryFromDashNumberError<T>; fn try_from(value: DashNumber<T>) -> Result<Self, Self::Error> { match value { DashNumber::NegInfinity => Err(TryFromDashNumberError::<T>::NegInfinity), DashNumber::Number(n) => { usize::try_from(n).map_err(|e| TryFromDashNumberError::<T>::Number(e)) } DashNumber::Infinity => Err(TryFromDashNumberError::<T>::Infinity), } } }
编译错误
error[E0275]: overflow evaluating the requirement `usize: TryFrom<_>` --> src/lib.rs:7:10 | 7 | #[derive(Debug)] | ^^^^^ | = help: consider increasing the recursion limit by adding a `#![recursion_limit = "256"]` attribute to your crate (`playground`) note: required for `usize` to implement `TryFrom<DashNumber<_>>` --> src/lib.rs:38:9 | 38 | impl<T> TryFrom<DashNumber<T>> for usize | ^^^^^^^^^^^^^^^^^^^^^^ ^^^^^ = note: 127 redundant requirements hidden = note: required for `usize` to implement `TryFrom<DashNumber<..nested DashNumber 125 times>>` = note: this error originates in the derive macro `Debug` (in Nightly builds, run with -Z macro-backtrace for more info) For more information about this error, try `rustc --explain E0275`.
错误原因
TryFromDashNumberError枚举定义上的where约束会迫使编译器递归检查:当T是DashNumber类型时,是否满足usize: TryFrom<T>。而TryFrom<DashNumber<T>>的实现又要求T满足usize: TryFrom<T>,形成无限递归推导,最终触发编译溢出。
解决方案
方法:移除枚举定义的约束,仅在impl块中添加必要约束
将TryFromDashNumberError枚举定义上的where约束移除,只在需要使用该类型的impl块中添加约束。这样可以避免编译器递归推导嵌套类型的约束。
修改后的完整代码:
use core::fmt; enum DashNumber<N> { NegInfinity, Number(N), Infinity, } #[derive(Debug)] enum TryFromDashNumberError<T: fmt::Debug> { NegInfinity, Number(<usize as TryFrom<T>>::Error), Infinity, } impl<T> fmt::Display for TryFromDashNumberError<T> where usize: TryFrom<T>, <usize as TryFrom<T>>::Error: std::error::Error + 'static, T: fmt::Debug, { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match self { TryFromDashNumberError::NegInfinity => { write!(f, "Negative infinity cannot be converted to a usize") } TryFromDashNumberError::Number(e) => { write!(f, "Error converting number to usize: {}", e) } TryFromDashNumberError::Infinity => { write!(f, "Infinity cannot be converted to a usize") } } } } impl<T> std::error::Error for TryFromDashNumberError<T> where usize: TryFrom<T>, <usize as TryFrom<T>>::Error: std::error::Error + 'static, T: fmt::Debug, {} impl<T> TryFrom<DashNumber<T>> for usize where usize: TryFrom<T>, <usize as TryFrom<T>>::Error: std::error::Error + 'static, T: fmt::Debug, { type Error = TryFromDashNumberError<T>; fn try_from(value: DashNumber<T>) -> Result<Self, Self::Error> { match value { DashNumber::NegInfinity => Err(TryFromDashNumberError::NegInfinity), DashNumber::Number(n) => { usize::try_from(n).map_err(TryFromDashNumberError::Number) } DashNumber::Infinity => Err(TryFromDashNumberError::Infinity), } } }
说明
- 移除
TryFromDashNumberError枚举定义的where约束,避免编译器提前递归检查嵌套类型的约束 - 在
fmt::Display、std::error::Error和TryFrom的impl块中添加必要的约束,确保只有符合条件的T才能使用该转换 - 简化
map_err的写法,提升代码可读性
内容的提问来源于stack exchange,提问作者Rainb
相关产品推荐
相关产品推荐

