Lifetimes in closures and recursive reference types

⚓ Rust    📅 2025-08-01    👤 surdeus    👁️ 11      

surdeus

Warning

This post was published 124 days ago. The information described in this article may have changed.

Hello, I’m trying to write 2D buffer and views into it. The pattern I’m trying to create is functions passed a reference to the view to the buffer or part of it. However I hit a wall concerning the lifetimes, as expected. The problem seems to me that I cannot model that passed reference to the closure ends with the calling function.

pub enum Frame<'a> {
    Buffer(Array3D<Cell>),
    View(&'a Frame<'a>, Rect),
    MutView(&'a mut Frame<'a>, Rect),
}

impl Frame<'_> {
    #[inline]
    pub fn bounds(&mut self, bounds: Rect, content: impl FnOnce(&mut Frame)) -> &mut Self {
        content(&mut Frame::MutView(self, bounds););
        self
    }
}

I tried having two lifetimes in the Frame, ’view and 'data, but that didn’t help.

My understanding is that, the closure content could store the reference somewhere, but it shouldn’t outlive it, but I can’t find a way to tell the compiler that.

 1  error: lifetime may not live long enough
    --> tmaze/src/renderer/mod.rs:360:40
     |
 357 | impl<'a> Frame<'a> {
     |      -- lifetime `'a` defined here
 358 |     #[inline]
 359 |     pub fn bounds(&mut self, bounds: Rect, content: impl FnOnce(&mut Frame<'a>)) -> &mut Self {
     |                   - let's call the lifetime of this reference `'1`
 360 |         let mut frame = Frame::MutView(self, bounds);
     |                                        ^^^^ this usage requires that `'1` must outlive `'a`
     |
     = note: requirement occurs because of a mutable reference to `renderer::Frame<'_>`
     = note: mutable references are invariant over their type parameter
     = help: see <https://doc.rust-lang.org/nomicon/subtyping.html> for more information about variance

 2  error[E0499]: cannot borrow `*self` as mutable more than once at a time
    --> tmaze/src/renderer/mod.rs:362:9
     |
 357 | impl<'a> Frame<'a> {
     |      -- lifetime `'a` defined here
 ...
 360 |         let mut frame = Frame::MutView(self, bounds);
     |                                        ----
     |                                        |
     |                                        first mutable borrow occurs here
     |                                        this usage requires that `*self` is borrowed for `'a`

This structure is rewrite of previous code, which used Frame trait and struct FrameView and struct FrameViewMut, but these didn’t suffer from this problem:

pub struct FrameViewMut<'a> {
    frame: &'a mut dyn Frame,
    bounds: Rect,
}

impl FrameViewMut<'_> {    
    pub fn bounds(
        &mut self,
        bounds: Rect,
        content: impl FnOnce(&mut FrameViewMut<'_>),
    ) -> &mut Self {
        content(&mut FrameViewMut {
            frame: self,
            bounds,
        });
        self
    }
}

Which I find particularly weird.

Thanks for any help.

4 posts - 3 participants

Read full topic

🏷️ Rust_feed