You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何避免自定义嵌套枚举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),
        }
    }
}

说明

  1. 移除TryFromDashNumberError枚举定义的where约束,避免编译器提前递归检查嵌套类型的约束
  2. 在fmt::Display、std::error::Error和TryFrom的impl块中添加必要的约束,确保只有符合条件的T才能使用该转换
  3. 简化map_err的写法,提升代码可读性

内容的提问来源于stack exchange,提问作者Rainb

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.07 23:31:05