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

Rust编译错误:`(dyn std::error::Error + 'static)`类型大小编译期未知

编译错误E0277:dyn Error无法确定大小问题解决

编译器错误信息

error[E0277]: the size for values of type `(dyn std::error::Error + 'static)` cannot be known at compilation time
   --> src/category.rs:117:47
    |
117 |         "Time" => get_input::<Time>(help_msg, get_value::<Time>(default_value))?.to_string(),
    |                   -----------------           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
    |                   |
    |                   required by a bound introduced by this call
    |
    = help: the trait `Sized` is not implemented for `(dyn std::error::Error + 'static)`
    = help: the trait `std::error::Error` is implemented for `Box<T>`
    = note: required for `Box<(dyn std::error::Error + 'static)>` to implement `std::error::Error`

关键函数签名

get_input函数

pub fn get_input<T: FromStr>(msg: &str, default_value: Option<T>) -> Result<T, Box<dyn Error>>
where
    T::Err: Error + 'static,
    T: std::fmt::Display,

get_value函数

fn get_value<T: FromStr>(value_str: &str) -> Option<T>
where
    T::Err: Error + 'static,

问题场景

代码处理u32、i32等内置类型时正常,但使用自定义Time结构体时触发错误:

let value: String = match type_str {
    "u32" => get_input::<u32>(help_msg, get_value::<u32>(default_value))?.to_string(),
    "i32" => get_input::<i32>(help_msg, get_value::<i32>(default_value))?.to_string(),
    "f32" => get_input::<f32>(help_msg, get_value::<f32>(default_value))?.to_string(),
    "bool" => get_input::<bool>(help_msg, get_value::<bool>(default_value))?.to_string(),
    "String" => get_input::<String>(help_msg, get_value::<String>(default_value))?.to_string(),
    // 触发错误的行
    "Time" => get_input::<Time>(help_msg, get_value::<Time>(default_value))?.to_string(),
    _ => "None".to_string(),
};

自定义Time结构体

use std::error::Error;

pub struct Time {
    hour: u8,
    minute: u8,
}

impl Time {
    pub fn new(hour: u8, minute: u8) -> Time {
        Time { hour, minute }
    }
}

impl std::str::FromStr for Time {
    type Err = Box<dyn Error + 'static>;
    fn from_str(s: &str) -> Result<Self, Self::Err> {
        let parts: Vec<&str> = s.split(':').collect();
        if parts.len() == 2 {
            let hour: u8 = parts[0].parse()?;
            let minute: u8 = parts[1].parse()?;
            Ok(Time::new(hour, minute))
        } else {
            Err("Invalid time format".into())
        }
    }
}

impl std::fmt::Display for Time {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        write!(f, "{:02}:{:02}", self.hour, self.minute)
    }
}

问题根源

问题出在Time的FromStr实现中,将关联类型Err定义为Box<dyn Error + 'static>:

  • 内置类型的FromStr::Err都是具体类型(如ParseIntError、ParseBoolError),这些类型实现了Error + 'static且是Sized的,能满足get_input和get_value的约束。
  • 而Box<dyn Error>作为错误类型时,虽然它本身是Sized的,但编译器在处理T::Err: Error约束时,会追溯到内部的dyn Error trait对象——dyn Error本身不满足Sized,导致编译报错。

修复方法

为Time定义自定义具体错误类型,替代Box<dyn Error>,让错误类型满足Error + 'static + Sized的要求:

1. 定义自定义错误类型

use std::error::Error;
use std::fmt;

#[derive(Debug)]
pub enum TimeParseError {
    /// 时间格式错误(不是HH:MM格式)
    InvalidFormat,
    /// 小时解析错误
    ParseHourError(std::num::ParseIntError),
    /// 分钟解析错误
    ParseMinuteError(std::num::ParseIntError),
}

impl fmt::Display for TimeParseError {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        match self {
            TimeParseError::InvalidFormat => write!(f, "无效的时间格式,应为HH:MM"),
            TimeParseError::ParseHourError(e) => write!(f, "小时解析失败:{}", e),
            TimeParseError::ParseMinuteError(e) => write!(f, "分钟解析失败:{}", e),
        }
    }
}

impl Error for TimeParseError {}

// 实现从ParseIntError到TimeParseError的转换,方便使用?操作符
impl From<std::num::ParseIntError> for TimeParseError {
    fn from(e: std::num::ParseIntError) -> Self {
        TimeParseError::ParseHourError(e)
    }
}

2. 修改Time的FromStr实现

impl std::str::FromStr for Time {
    type Err = TimeParseError;
    fn from_str(s: &str) -> Result<Self, Self::Err> {
        let parts: Vec<&str> = s.split(':').collect();
        if parts.len() == 2 {
            // 分别处理小时和分钟的解析错误,更精准
            let hour = parts[0].parse().map_err(TimeParseError::ParseHourError)?;
            let minute = parts[1].parse().map_err(TimeParseError::ParseMinuteError)?;
            Ok(Time::new(hour, minute))
        } else {
            Err(TimeParseError::InvalidFormat)
        }
    }
}

修改后,Time的错误类型是具体的TimeParseError,和内置类型的错误类型一致,能够满足get_input和get_value的约束,编译错误即可解决。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.17 22:56:59