4

I have some code like this

struct A<'a> {
    b: B,
    c: C<'a>,
}

struct B {}

struct C<'a> {
    b: &'a B
}

impl<'a> A<'a> {
    fn new() -> Self {
        let b = B {};

        Self {
            b,
            c: C { b: &b },
        }
    }
}

where I get the error

error[E0515]: cannot return value referencing local variable `b`
  --> src/dummy.rs:16:9
   |
16 | /         Self {
17 | |             b,
18 | |             c: C { b: &b },
   | |                       -- `b` is borrowed here
19 | |         }
   | |_________^ returns a value referencing data owned by the current function

error[E0382]: borrow of moved value: `b`
  --> src/dummy.rs:18:23
   |
14 |         let b = B {};
   |             - move occurs because `b` has type `B`, which does not implement the `Copy` trait
...
17 |             b,
   |             - value moved here
18 |             c: C { b: &b },
   |                       ^^ value borrowed here after move

Some errors have detailed explanations: E0382, E0515.
For more information about an error, try `rustc --explain E0382`.

I think I understand the error, that of course b has a transferred ownership to that new object of A and therefore it seems like there is no guarantee for the lifetime of the object of C when it borrows from B. However because the object of C has its ownership also transferred to the object of A, the lifetime of the object of C as well as b should be the same, right?

How can I express that in Rust that I can create objects of A where I have an object of B and an object of C that also references to that object of B as B and C will have the same lifetime (the one of A)?

h345k34cr
  • 3,310
  • 5
  • 21
  • 28
  • 2
    Does this work for you? https://stackoverflow.com/questions/30823880/struct-that-owns-some-data-and-a-reference-to-the-data Otherwise you could look into arena allocators, in any case your struct cannot be moved anymore because this would invalidate the reference – Unlikus Jul 30 '22 at 11:14
  • So the best way would be to give the ownership of B to C and just keep a reference of B in A? Let's say we will have another object D that works the same as C: also resides in A and wants to have a reference to B. Then this wouldn't work any more, right? – h345k34cr Jul 30 '22 at 11:24
  • You basically cannot have an object and a reference to it in the same struct. When you really need this the object has to be in the heap (so Box or other smart pointer types). Because of the lifetime problem you probably need a Rc, if you can pay the runtime price I would recommend this. – Unlikus Jul 30 '22 at 11:28

1 Answers1

2

As pointed out in the comments and the duplicate question, you can't.

If you want to keep your current code structure, you are forced to use reference counters.

use std::{cell::RefCell, rc::Rc};

struct A {
    b: Rc<RefCell<B>>,
    c: C,
}

struct B {}

struct C {
    b: Rc<RefCell<B>>,
}

impl A {
    fn new() -> Self {
        let b = Rc::new(RefCell::new(B {}));

        Self {
            b: b.clone(),
            c: C { b },
        }
    }
}

However, I think it would be more benefitial to refactor your code structure to avoid this problem in the first place. This of course depends on the specific usecase.

Finomnis
  • 18,094
  • 1
  • 20
  • 27