rustc 无法推断 trait 实现中的生存期

rustc cannot infer lifetime in trait implementations

提问人:gust 提问时间:10/28/2023 更新时间:10/28/2023 访问量:50

问:

我有以下代码:

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

即使应该能够推断生存期,也无法这样做。最直接的方法是添加显式生存期签名;但是,在本例中,这是一个特征实现(std::convert::TryFrom),因此我无法更改函数签名。有没有办法解决这个问题?try_fromrustc

蚀性 状寿命

评论

1赞 Ry- 10/28/2023
impl<'a> TryFrom<&'a Value> for &'a InnerValue和?我不完全熟悉什么样的推理是可能的,但似乎不应该有规则,然后为时已晚?fn try_from(value: &'a Value)impl TryFrom<&Value> for &InnerValue
0赞 cafce25 10/28/2023
Rust 对函数根本没有生命周期推断,只有对闭包的生命周期推断,但事实并非如此。 Elision 类似,但有非常严格的规则。
0赞 cafce25 10/28/2023
我也不清楚你所说的“无法更改函数签名”是什么意思,因为根本不需要进行编译
0赞 BallpointBen 10/28/2023
没有理由,首先应该具有相同的寿命。没有什么可推断的,因为已经由时间决定了,需要推断出的寿命。&InnerValuevalue: &ValueSelftry_from

答:

1赞 Anders Evensen 10/28/2023 #1

虽然您不能更改 的函数签名,但您可以在实现 时指定显式生存期,如下所示: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)。

不期望能够省略和相同的生命周期;请参阅 Rustonomicon 的 Lifetime Elision 部分,特别是以下行:“对于标头,所有类型都是输入的。所以在输入位置上省略了两个寿命,而省略了一个。因此,如果要使它们相同,则必须显式提供这两个生存期。rustc&Value&InnerValueimplimpl Trait<&T> for Struct<&T>impl Struct<&T>