3

The following code doesn't compile:

use std::borrow::Borrow;

struct Inner<'a> {
    v: Vec<&'a u8>,
}

struct Foo<'a> {
    inner: Inner<'a>,
    derp: Box<u8>,
}

impl<'a> Foo<'a> {
    fn new() -> Foo<'a> {
        let mut e = Foo {
            inner: Inner { v: vec![] },
            derp: Box::new(128),
        };
        e.inner.v.push(&*e.derp);

        return e;
    }

    fn derp(&mut self) {
        println!("{:?}", self.inner.v);
    }
}

fn main() {
    let mut f = Foo::new();

    f.derp();
}

I get the following error:

error[E0597]: `*e.derp` does not live long enough
  --> src/main.rs:18:25
   |
18 |         e.inner.v.push(&*e.derp);
   |                         ^^^^^^^ does not live long enough
...
21 |     }
   |     - borrowed value only lives until here
   |
note: borrowed value must be valid for the lifetime 'a as defined on the impl at 12:1...
  --> src/main.rs:12:1
   |
12 | / impl<'a> Foo<'a> {
13 | |     fn new() -> Foo<'a> {
14 | |         let mut e = Foo {
15 | |             inner: Inner { v: vec![] },
...  |
25 | |     }
26 | | }
   | |_^

I think that the value inside of the box does live for as long as 'a since it is a member of Foo, which has exactly that lifetime.

I wondered if the move of Foo at the end of the new function was confusing it, so if tried to do the append in derp. I get a different error:

error[E0495]: cannot infer an appropriate lifetime for borrow expression due to conflicting requirements
  --> main.rs:20:27
   |
20 |         self.inner.v.push(& *self.derp);
   |                           ^^^^^^^^^^

which gives me no indication of what lifetime the compiler thinks the boxed value has.

Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366
Bob Bobbio
  • 577
  • 2
  • 5
  • 10

1 Answers1

3

I think though that the value inside of the box does live for as long as 'a since it is a member of Foo which has exactly that lifetime.

It is possible to assign a new box to the derp member, at which point the old box will be dropped and the lifetime of the value in it ends.

I think what you are trying to do is impossible in safe Rust: cross-references between struct members are not supported. This comes up regularly as a question, but it's just not available in the language.

You can use Rc to work around this, perhaps in combination with RefCell.

Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366
Florian Weimer
  • 32,022
  • 3
  • 48
  • 92
  • ah, I see. I suppose that makes sense. I wonder if there is any way to stop this from being possible and force the box to live for the whole lifetime of 'a. – Bob Bobbio Jul 26 '17 at 06:36