我有以下代码:
use anyhow;
struct InnerValue;
enum Value {
Int(i32),
Other(InnerValue),
}
impl TryFrom<&Value> for &InnerValue {
type Error = anyhow::Error;
fn try_from(value: &Value) -> Result<Self, Self::Error> {
match value {
Value::Int(..) => anyhow::bail!("Ignore this case"),
Value::Other(inner) => Ok(inner)
}
}
}
rustc
告诉我:
Compiling playground v0.0.1 (/playground)
error: lifetime may not live long enough
--> src/lib.rs:16:36
|
13 | fn try_from(value: &Value) -> Result<Self, Self::Error> {
| - ------------------------- return type is Result<&'2 InnerValue, <&'2 InnerValue as TryFrom<&Value>>::Error>
| |
| let's call the lifetime of this reference `'1`
...
16 | Value::Other(inner) => Ok(inner)
| ^^^^^^^^^ associated function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1`
error: could not compile `playground` (lib) due to previous error
尽管
try_from
应该能够推断生命周期,但 rustc
却无法做到这一点。最直接的方法是添加显式的生命周期签名;然而,在这种情况下,这是一个特征实现(std::convert::TryFrom
),所以我无法更改函数签名。有办法解决这个问题吗?
虽然您无法更改
try_from()
的函数签名,但您 可以
在实现 TryFrom
时指定显式的生命周期,如下所示:
impl<'a> TryFrom<&'a Value> for &'a InnerValue {
type Error = anyhow::Error;
fn try_from(value: &'a Value) -> Result<Self, Self::Error> {
match value {
Value::Int(..) => anyhow::bail!("Ignore this case"),
Value::Other(inner) => Ok(inner)
}
}
}
这将按照您的预期进行编译(请参阅playground)。
预计
rustc
不能将&Value
和&InnerValue
的生命周期消除到相同的生命周期;请参阅 Rustonomicon 的 Lifetime Elision 部分,特别是以下行:“对于 impl
标头,所有类型都是输入。因此 impl Trait<&T> for Struct<&T>
在输入位置中省略了两个生命周期,而 impl Struct<&T>
则省略了一个。”因此,如果两个生命周期要相同,则必须明确提供它们。