我正在尝试通过实现 std::error::Error
创建自定义错误类型以在我的 Rust 项目中使用。我还创建了一个小的快捷函数来创建 std::io::Error
。不幸的是,我受困于生命周期,所以我寻求帮助:
use std::error::Error;
use std::fmt;
use std::io;
#[derive(Debug)]
pub struct BadString<'a> {
desc: &'a str,
}
impl<'a> BadString<'a> {
pub fn new(desc: &str) -> BadString {
BadString{ desc: desc }
}
}
impl<'a> Error for BadString<'a> {
fn description(&self) -> &str { &self.desc }
}
impl<'a> fmt::Display for BadString<'a> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.write_str(self.description())
}
}
fn bad_str_err(desc: &str) -> io::Error {
let err = BadString::new(desc);
io::Error::new(io::ErrorKind::Other, err)
}
fn main() {
}
这会报告错误:
<anon>:27:30: 27:34 error: cannot infer an appropriate lifetime for automatic coercion due to conflicting requirements
<anon>:27 let err = BadString::new(desc);
^~~~
<anon>:28:5: 28:46 note: first, the lifetime cannot outlive the call at 28:4...
<anon>:28 io::Error::new(io::ErrorKind::Other, err)
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
<anon>:28:42: 28:45 note: ...so that argument is valid for the call
<anon>:28 io::Error::new(io::ErrorKind::Other, err)
^~~
<anon>:27:30: 27:34 note: but, the lifetime must be valid for the expression at 27:29...
<anon>:27 let err = BadString::new(desc);
^~~~
<anon>:27:30: 27:34 note: ...so that auto-reference is valid at the time of borrow
<anon>:27 let err = BadString::new(desc);
^~~~
error: aborting due to previous error
playpen: application terminated with error code 101
我不确定如何修复它以便编译。
最佳答案
我们来看 io::Error::new
的签名:
fn new<E>(kind: ErrorKind, error: E) -> Error
where E: Into<Box<Error + Send + Sync>>
这表明 error
可以是任何类型,只要该类型实现了特征 Into<Box<Error + Send + Sync>>
.该特征意味着该类型可以转换为装箱特征对象。特征对象本身必须实现特征 Error
, Send
和 Sync
.不明显的是,默认情况下,特征对象也有一个 'static
。 lifetime bound(这是有道理的,但它似乎确实让人绊倒)。
让我们尝试自己进行转换:
fn bad_str_err(desc: &str) -> io::Error {
let err = BadString::new(desc);
let foo: Box<Error + Send + Sync + 'static> = err.into();
}
我们得到了同样的错误——“由于需求冲突,无法推断出自动强制转换的适当生命周期”。所以我们的问题就在于能否转换为这个trait对象。
Send
和 Sync
是两个关键特征,有助于指导编译器了解哪些类型可以安全地在线程之间发送/共享。为了在线程之间安全地共享某些东西,它不能在另一个线程拥有它时“消失”。这是 Rust 在编译时帮助防止的一种错误。
在这种情况下,您打算使用一个字符串切片 ( &str
),但该切片不拥有底层内存,它只是引用它。一旦该内存超出范围,任何引用都需要变为无效。这是 Rust 在编译时阻止的另一件事。
在这种情况下,最简单的做法就是不使用引用:
use std::error::Error;
use std::{fmt, io};
#[derive(Debug)]
pub struct BadString {
desc: String,
}
impl BadString {
pub fn new(desc: &str) -> BadString {
BadString { desc: desc.into() }
}
}
impl Error for BadString {
fn description(&self) -> &str { &self.desc }
}
impl fmt::Display for BadString {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.write_str(self.description())
}
}
fn bad_str_err(desc: &str) -> io::Error {
let err = BadString::new(desc);
io::Error::new(io::ErrorKind::Other, err)
}
fn main() {}
A String
拥有底层内存,因此它可以安全地跨线程边界传输,无需担心任何其他对象被意外释放。
关于rust - 如何使用具有生命周期的类型作为 io::Error::new 的 `error` 参数?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34030455/