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 Errortrait对象——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
相关产品推荐
相关产品推荐

