如何在包含引用时返回错误?

时间:2016-03-31 12:40:22

标签: rust borrow-checker

我有一个返回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]

Playground

1 个答案:

答案 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

这种方法不允许您动态创建错误消息(您只能使用字符串文字来表示错误消息),但它更有效,因为它不需要为程序中的不愉快路径分配,它可能足以满足您的使用案例。