How do I specify lifetimes such that a local referenced value is distinct from a passed in reference?

时间:2019-04-08 12:47:12

标签: rust lifetime

I'm creating a local struct (second) which contains a reference to a local variable (wrapper). This local variable, in turn, references a larger lifetime ('a). How do I show the compiler, that the lifetime of the local variable doesn't need to be as large as that larger lifetime?

This problem is reproduced by the following code (playground):

#![allow(dead_code)]
use std::marker::PhantomData;

trait Abc {}

struct ImplAbc;
impl Abc for ImplAbc {}

struct WrappingAbc<'a, A> {
    value: &'a A,
}
impl<'a, A: Abc> Abc for WrappingAbc<'a, A> {}
impl<'a, A: Abc> WrappingAbc<'a, A> {
    fn new(value: &'a A) -> Self {
        WrappingAbc { value }
    }
}

struct AnotherWrapper<'a, K, A, S> {
    value: &'a A,
    other: usize,
    phantom_data: PhantomData<(K, S)>,
}
impl<'a, A: Abc, S: Strategy<KindOne, A>> AnotherWrapper<'a, KindOne, A, S> {
    fn new(value: &'a A) -> Self {
        AnotherWrapper {
            value,
            other: 0,
            phantom_data: PhantomData,
        }
    }
}
impl<'a, 'b, A: Abc, S: Strategy<KindTwo, WrappingAbc<'b, A>>>
    AnotherWrapper<'a, KindTwo, WrappingAbc<'b, A>, S>
{
    fn replace_value<SOther: Strategy<KindOne, A>>(
        old: AnotherWrapper<KindOne, A, SOther>,
        newvalue: &'a WrappingAbc<'b, A>,
    ) -> Self {
        AnotherWrapper {
            value: newvalue,
            other: old.other,
            phantom_data: PhantomData,
        }
    }
}
trait Kind {}
struct KindOne;
impl Kind for KindOne {}
struct KindTwo;
impl Kind for KindTwo {}

trait Strategy<K: Kind, A: Abc>: Sized {}
struct StrategyImpl;
impl<K: Kind, A: Abc> Strategy<K, A> for StrategyImpl {}

fn f<'a, A: Abc, SOne: Strategy<KindOne, A>, STwo: Strategy<KindTwo, WrappingAbc<'a, A>>>(
    x: &'a A,
) {
    let first = AnotherWrapper::<KindOne, A, SOne>::new(x);
    let wrapper = WrappingAbc::new(x);
    let second = AnotherWrapper::<KindTwo, WrappingAbc<A>, STwo>::replace_value(first, &wrapper);
    move_away(second);
}

fn move_away<'a, A: Abc, S: Strategy<KindTwo, WrappingAbc<'a, A>>>(
    _argument: AnotherWrapper<'a, KindTwo, WrappingAbc<'a, A>, S>,
) {
}
error[E0597]: `wrapper` does not live long enough
  --> src/lib.rs:62:88
   |
57 | fn f<'a, A: Abc, SOne: Strategy<KindOne, A>, STwo: Strategy<KindTwo, WrappingAbc<'a, A>>>(
   |      -- lifetime `'a` defined here
...
62 |     let second = AnotherWrapper::<KindTwo, WrappingAbc<A>, STwo>::replace_value(first, &wrapper);
   |                  ----------------------------------------------------------------------^^^^^^^^-
   |                  |                                                                     |
   |                  |                                                                     borrowed value does not live long enough
   |                  argument requires that `wrapper` is borrowed for `'a`
63 |     move_away(second);
64 | }
   | - `wrapper` dropped here while still borrowed

How can I change the lifetime definitions such that wrapper is not required to live as long as 'a, given that second is moved right after anyways? I suspect that this is related to the definition of move_away, because when I modify that line to this (playground):

fn move_away<'a, A: Abc, S: Strategy<KindTwo, A>>(_argument: AnotherWrapper<'a, KindTwo, A, S>) {}

the code compiles.

1 个答案:

答案 0 :(得分:1)

move_away的定义更改为以下内容可以解决编译错误:

fn move_away<'a, 'b, A: Abc, S: Strategy<KindTwo, WrappingAbc<'b, A>>>(
    _argument: AnotherWrapper<'a, KindTwo, WrappingAbc<'b, A>, S>
) {}

引入生存期'b消除了内部WrappingAbc的生存期与父函数指定的'a一样长的要求。