RefMut::filter_map and confusing lifetime error

⚓ Rust    📅 2025-07-07    👤 surdeus    👁️ 5      

surdeus

If I try to compile this, the get_tic method produces an error that I don't understand.

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

#[derive(Default)]
struct Window {
    widget: Option<Rc<RefCell<dyn Widget>>>
}

trait Widget {
    fn as_text_input_client(&mut self) -> Option<&mut dyn TextInputClient> { None }
}
trait TextInputClient {
    fn insert_text(&mut self, text: &str);
}

impl Window {
    fn get_tic(&mut self) -> Option<RefMut<'_, dyn TextInputClient>> {
        let wid = self.widget.as_ref()?;
        RefMut::filter_map(wid.borrow_mut(), |b| {
            b.as_text_input_client()
        }).ok()
    }

    fn insert_text(&mut self) {
        if let Some(mut tic) = self.get_tic() {
            tic.insert_text("hi");
        }
    }
}

Error:

error: lifetime may not live long enough
  --> learning/question1.rs:22:13
   |
21 |         RefMut::filter_map(wid.borrow_mut(), |b| {
   |                                               -- return type of closure is Option<&mut (dyn TextInputClient + '2)>
   |                                               |
   |                                               has type `&'1 mut dyn Widget`
22 |             b.as_text_input_client()
   |             ^^^^^^^^^^^^^^^^^^^^^^^^ returning this value requires that `'1` must outlive `'2`
   |
   = note: requirement occurs because of a mutable reference to `dyn TextInputClient`
   = note: mutable references are invariant over their type parameter
   = help: see <https://doc.rust-lang.org/nomicon/subtyping.html> for more information about variance

From what I know about lifetimes, the expanded version of as_text_input_client should look like:

fn as_text_input_client<'a>(&'a mut self) -> Option<&'a mut dyn TextInputClient>

And that looks okay, but apparently it is creating another lifetime '2 and using it: (dyn TextInputClient + '2). What is that?

3 posts - 2 participants

Read full topic

🏷️ rust_feed