我有一个返回State
的Rust方法。此方法在MyError
结构上运行,'a
具有生命周期说明符&str
,因为它需要保留一些trait MyTrait {
type Error;
fn work(&self) -> Result<(), Self::Error>;
}
impl<'a> MyTrait for MyImpl<'a> {
type Error = MyError<'a>;
fn work(&self) -> Result<(), MyError<'a>> {
let state = State::new();
state.work() // returns Result<(), MyError> but state doesn't live long enough
}
}
。
我试图写出这样的特征:
MyError
如何解决此错误?我应该更改String
以保留&'a str
而不是state
吗?我应该将MyImpl
保留在trait
内吗?这个State
定义明确吗?
我想为do()
的每次运行创建一个enum MyError<'a> {
Some(&'a str),
}
trait MyTrait {
type Error;
fn work(&self) -> Result<(), Self::Error>;
}
struct MyImpl<'a> {
pub some_string: &'a str,
}
impl<'a> MyTrait for MyImpl<'a> {
type Error = MyError<'a>;
fn work(&self) -> Result<(), MyError<'a>> {
let state = State::new();
state.work() // returns Result<(), MyError> but state doesn't live long enough
}
}
struct State;
impl State {
pub fn new() -> State {
State
}
pub fn work(&self) -> Result<(), MyError> {
Err(MyError::Some("hi"))
}
}
fn main() {}
。
这是一个MCVE:
System.Collections.Generic.List'1[System.Int32]
答案 0 :(得分:2)
问题在于,根据State::work()
的签名,MyError
的生命周期参数与&self
引用的生命周期参数相关联:
// without lifetime elision
pub fn work<'a>(&'a self) -> Result<(), MyError<'a>>
然后在MyImpl::work()
:
fn work(&self) -> Result<(), MyError<'a>> {
let state = State::new();
state.work()
}
问题是,'a
中的生命周期参数impl<'a> MyTrait for MyImpl<'a>
表示严格大于的生命周期<{1}}返回的MyError
生命周期。为什么会这样?好吧,让我们再看看State::work()
:
MyImpl::work()
请注意fn work(&self) -> Result<(), MyError<'a>> {
let state = State::new();
state.work()
}
返回State::work(&self)
,其生命周期与MyError
的生命周期相关联,也就是说,在此特定情况下,它将是&self
的生命周期。后者是一个局部变量,在state
返回后立即被销毁。
但是,work()
中的'a
表示存储在impl<'a> MyTrait for MyImpl<'a>
中的字符串切片的生命周期(即MyImpl
)。当然,因为self
可以被调用,这意味着它被调用的值处于有效状态并且保持一个活着的切片。因此,它的生命周期大于MyImpl::work()
内可以创建的任何内容。因此,在MyImpl::work()
内返回未从此字符串切片派生的任何内容是不合理的;例如,这是有效的:
MyImpl
现在impl<'a> MyTrait for MyImpl<'a> {
type Error = MyError<'a>;
fn work(&self) -> Result<(), MyError<'a>> {
Err(MyError::Some(self.some_string))
}
}
值的生命周期恰好是MyError
的生命周期,借用检查器会变得快乐。
现在,有哪些选择?首先,最简单的方法是在self.some_string
内存储一个拥有的String
:
MyError
我认为,这是最惯用,最灵活的方法。具有非自足的错误值实际上非常罕见;我想我之前从未见过。另一种选择是使用enum MyError {
Some(String)
}
impl<'a> MyTrait for MyImpl<'a> {
type Error = MyError;
fn work(&self) -> Result<(), MyError> {
let state = State::new();
state.work()
}
}
struct State;
impl State {
pub fn new() -> State {
State
}
pub fn work(&self) -> Result<(), MyError> {
Err(MyError::Some("hi".into()))
}
}
:
&'static str
这种方法不允许您动态创建错误消息(您只能使用字符串文字来表示错误消息),但它更有效,因为它不需要为程序中的不愉快路径分配,它可能足以满足您的使用案例。