Felix Chapman
Felix Chapman

Reputation: 91

Using a struct containing a borrowed parameter

I'm writing a simple game in Rust, which includes a Drawer, which is constructed once and then passed through many methods as a mutable reference:

pub struct Drawer<'a> {
    // ...
    renderer: Renderer<'a>,
    // ...
}

fn pause(drawer: &mut Drawer, events: &[Event]) {
    // ...
    drawer.draw_text(&TextPos::Centered, "Paused", 1);
    // ...
}

I wanted to refactor my code to introduce a fluent interface for drawing text, such as:

drawer.text()
    .size(4)
    .centered()
    .draw("Paused");

I did this by creating a TextDrawer struct, that contains a reference to the Drawer:

pub struct TextDrawer<'a, 'b: 'a> {
    pos: TextPos,
    size: u32,
    drawer: &'a mut Drawer<'b>,
}

impl<'a> Drawer<'a> {
     pub fn text(&mut self) -> TextDrawer {
        TextDrawer {
            pos: TextPos::At(0, 0),
            size: 1,
            drawer: self,
        }
    }
}

I think the lifetimes I've put on the struct are correct (the reference must last as long as the Drawer itself).

However, my text method will not compile until I add explicit lifetimes. When I do, every method that calls text then demands explicit lifetimes, and so on. I'm surprised these lifetimes have to be stated: after all, they're all of the form fn foo<'a, 'b: 'a>(drawer: &mut'a Drawer<'b>). I had assumed before this point that this was already the inferred lifetime, since it was always necessary for the reference to last as long as the Drawer itself.

Is it necessary for me to put these explicit lifetimes all other my method signatures? Or can I avoid it in some other way?

Upvotes: 0

Views: 123

Answers (1)

Felix Chapman
Felix Chapman

Reputation: 91

Thanks to the minimal example made by Lukas above, I realised I had simply got the lifetime parameters to my text method backwards.

My incorrect lifetimes:

impl<'a> Drawer<'a> {
    pub fn text<'b>(&'b mut self) -> TextDrawer<'a, 'b> {
        // omitted
    }
}

The correct lifetimes:

impl<'a> Drawer<'a> {
    pub fn text<'b>(&'b mut self) -> TextDrawer<'b, 'a> {
        // omitted
    }
}

After this, everything compiles without any further explicit lifetimes.

Upvotes: 1

Related Questions