让我们专注于您的问题的绝对最小重现:
use std::error::Error;
fn foo() -> Result<String, Box<dyn Error>> {
Err("Error...")
}
这段代码返回的错误是:
error[E0308]: mismatched types
--> src/lib.rs:4:9
|
4 | Err("Error...")
| ^^^^^^^^^^ expected struct `std::boxed::Box`, found reference
|
= note: expected type `std::boxed::Box<dyn std::error::Error>`
found type `&'static str`
这是说函数签名希望您返回一个包含Box<dyn Error> 的Err,但实际上您返回了一个包含&str 的Err。由于类型不对齐,编译器会抛出错误。
解决这个问题的最简单方法是使用Into trait,它实现了&str 和Box<dyn Error> 之间的转换:
use std::error::Error;
fn foo() -> Result<String, Box<dyn Error>> {
Err("Error...".into())
// `Err(Box::from("Error..."))` would also work
}
工作原理
您可能仍然想知道 .into() 调用在幕后究竟做了什么。
首先,让我们看看如果我们只使用 Box 和 &str 会发生什么:
use std::error::Error;
fn foo() -> Result<String, Box<dyn Error>> {
Err(Box::new("Error..."))
}
error[E0277]: the trait bound `&str: std::error::Error` is not satisfied
--> src/lib.rs:4:9
|
4 | Err(Box::new("Error..."))
| ^^^^^^^^^^^^^^^^^^^^ the trait `std::error::Error` is not implemented for `&str`
|
= note: required for the cast to the object type `dyn std::error::Error`
同样,这不起作用,因为类型不对齐 - 它期望 Box 包含实现 Error 特征的东西,但如果你 look at the docs,你会注意到 @987654339 @ 不是实现它的类型之一。你需要将你的字符串包装成一个实现Error的类型:
use std::error::Error;
use std::fmt;
#[derive(Debug)]
struct StrError<'a>(&'a str);
// Error doesn't require you to implement any methods, but
// your type must also implement Debug and Display.
impl<'a> Error for StrError<'a> {}
impl<'a> fmt::Display for StrError<'a>{
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
// Delegate to the Display impl for `&str`:
self.0.fmt(f)
}
}
fn foo() -> Result<String, Box<dyn Error>> {
Err(Box::new(StrError("Error...")))
}
这段代码可以编译,基本上就是 impl Into<Box<dyn Error>> for &str 在幕后所做的 :)