razielgn
razielgn

Reputation: 46

Borrow pointer of a value which will be moved in a struct

Let's say a Manager holds references to a Designer and a Programmer, but the Programmer also has to hold a reference to a Designer, in order to ping them whenever they want.

The problem is, by creating both the Designer and the Programmer in Manager::new(), the &designer reference doesn't live long enough, since in the following lines, it gets moved inside the Manager.

The error is 'designer' does not live long enough.

struct Programmer<'a> {
    designer: &'a Designer,
}

impl<'a> Programmer<'a> {
    pub fn new(designer: &'a Designer) -> Programmer<'a> {
        Programmer { designer: designer }
    }
}

struct Designer {
    iq: u32,
}

impl Designer {
    pub fn new(iq: u32) -> Designer {
        Designer { iq: iq }
    }
}

struct Manager<'a> {
    programmer: Programmer<'a>,
    designer: Designer
}

impl<'a> Manager<'a> {
    pub fn new() -> Manager<'a> {
        let designer = Designer::new(42);
        let programmer = Programmer::new(&designer);

        Manager { designer: designer, programmer: programmer }
    }
}

fn main() {
    Manager::new();
}

Compilation fails with this message:

test.rs:29:47: 29:55 error: `designer` does not live long enough
test.rs:29             let programmer = Programmer::new(&designer);
                                                         ^~~~~~~~
test.rs:27:37: 32:10 note: reference must be valid for the lifetime 'a as defined on the block at 27:36...
test.rs:27         pub fn new() -> Manager<'a> {
test.rs:28             let designer = Designer::new(42);
test.rs:29             let programmer = Programmer::new(&designer);
test.rs:30
test.rs:31             Manager { designer: designer, programmer: programmer }
test.rs:32         }
test.rs:27:37: 32:10 note: ...but borrowed value is only valid for the block at 27:36
test.rs:27         pub fn new() -> Manager<'a> {
test.rs:28             let designer = Designer::new(42);
test.rs:29             let programmer = Programmer::new(&designer);
test.rs:30
test.rs:31             Manager { designer: designer, programmer: programmer }
test.rs:32         }

How could I fix this problem, without injecting the Designer via Manager::new(&designer)?

Upvotes: 1

Views: 87

Answers (1)

Jorge Israel Pe&#241;a
Jorge Israel Pe&#241;a

Reputation: 38626

I imagine you know what you're doing, but that doesn't seem like the best design to use with Rust. You say a Programmer should hold a reference to a Designer in order to ping them, but I imagine that pinging them implies mutating the Designer in some way (e.g. imagine some is_pinged field on the Designer), which you can't do via a simple reference. All you can do through a regular, immutable reference is read the data or call methods which don't mutate the variable. What's more, so long as you have that reference, the original Designer cannot be mutated.

If you do just want to have an immutable reference though, then you can use the Rc type, which provides an immutable reference-counted pointer.

If you want to somehow allow the Programmer to send messages to the Designer which may or may not trigger mutations on the Designer, then you can try using channels. Each Designer would store its own channel, and it could have a method which clones the Sender end of the channel for an interested Programmer to store and use.

Upvotes: 2

Related Questions