How to fix:`self` has an anonymous lifetime `'_` but it needs to satisfy a `'static` lifetime requirement

I want to update the value of struct member in a static closure, but got errors

`self` has an anonymous lifetime `'_` but it needs to satisfy a `'static` lifetime requirement

How to fix it?

use std::future::Future;
use std::pin::Pin;
use std::sync::Arc;
use tokio::sync::Mutex;

pub type OnReadyFn =
    Box<dyn (FnMut() -> Pin<Box<dyn Future<Output = ()> + Send + 'static>>) + Send + Sync>;
pub struct Pen {
    pub on_ready_handler: Arc<Mutex<Option<OnReadyFn>>>,
}

impl Pen {
    fn new() -> Self {
        Self {
            on_ready_handler: Arc::new(Mutex::new(None)),
        }
    }
    pub async fn on_ready(&self, f: OnReadyFn) {
        let mut handler = self.on_ready_handler.lock().await;
        *handler = Some(f);
    }
}

pub struct Person {
    pen: Pen,
    state: u32,
}

impl Person {
    fn new() -> Self {
        Self {
            pen: Pen::new(),
            state: 0,
        }
    }

    async fn init(&mut self) {
        self.pen
            .on_ready(Box::new(move || {
                self.state = 2;
                Box::pin(async {})
            }))
            .await;
    }
}

The closure

move || {
    self.state = 2;
    Box::pin(async {})
}

captures a mutable reference to self.state and the call to on_ready places this closure into the self.pen field. You’re creating a self-referencing struct here... this won’t work as easily. Actually, on a second thought, the closure doesn’t capture a mutable reference to self.state because it’s a move closure; instead it moves self: &mut Person into the closure. Still that’s a short-lived mutable reference incompatible with the (implicit “+ 'static”) requirement of Box<dyn FnMut(…) -> … + …>. Also, moving self like this introduces a conflict with the use of self.pen; that’s an error message you’d get if you e.g. turn the function into fn init(&'static mut self).

Anyway… One possible workaround is to introduce yet another Arc<Mutex<…>> around state. Or perhaps make it an Arc<AtomicU32>.

+ use std::sync::atomic::{AtomicU32, Ordering::SeqCst};
use std::future::Future;
use std::pin::Pin;
use std::sync::Arc;
use tokio::sync::Mutex;

pub type OnReadyFn =
    Box<dyn (FnMut() -> Pin<Box<dyn Future<Output = ()> + Send + 'static>>) + Send + Sync>;
pub struct Pen {
    pub on_ready_handler: Arc<Mutex<Option<OnReadyFn>>>,
}

impl Pen {
    fn new() -> Self {
        Self {
            on_ready_handler: Arc::new(Mutex::new(None)),
        }
    }
    pub async fn on_ready(&self, f: OnReadyFn) {
        let mut handler = self.on_ready_handler.lock().await;
        *handler = Some(f);
    }
}

pub struct Person {
    pen: Pen,
-   state: u32,
+   state: Arc<AtomicU32>,
}

impl Person {
    fn new() -> Self {
        Self {
            pen: Pen::new(),
-           state: 0,
+           state: Arc::new(0.into()),
        }
    }

    async fn init(&mut self) {
+       let state = Arc::clone(&self.state);
        self.pen
            .on_ready(Box::new(move || {
-               self.state = 2;
+               state.store(2, SeqCst);
                Box::pin(async {})
            }))
            .await;
    }
}
1 Like

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.