Closure lifetime issue, argument requires that `'1` must outlive `'static`

Hey, folks.
I'm a rust beginner. How could I fix this issue?

pub struct Context<'env> {
  raw: &'env *mut String,
}

fn closure<F>(callback: F) -> ()
where
  F: Send + Fn(Context<'_>) + 'static,
{
}

pub(crate) struct SafeContext<'e>(Context<'e>);

unsafe impl<'e> Send for SafeContext<'e> {}
unsafe impl<'e> Sync for SafeContext<'e> {}

fn main() {
  let rt = tokio::runtime::Builder::new_multi_thread().build().unwrap();
  let _guard = rt.enter();

  closure(move |ctx: Context<'_>| {
    let s_ctx = SafeContext(ctx);

    rt.spawn(async {
      let a = s_ctx;
      
    });
  });
}

Error

error[E0521]: borrowed data escapes outside of closure
  --> src\main.rs:22:5
   |
19 |     closure(move |ctx: Context<'_>| {
   |                   ---
   |                   |
   |                   `ctx` is a reference that is only valid in the closure body
   |                   has type `Context<'1>`
...
22 | /     rt.spawn(async {
23 | |       let a = s_ctx;
24 | |       
25 | |     });
   | |      ^
   | |      |
   | |______`ctx` escapes the closure body here
   |        argument requires that `'1` must outlive `'static`

Use owned data[1]:

pub struct Context {
    raw: String,
}

fn closure<F>(callback: F) -> ()
where
    F: Send + Fn(Context) + 'static,
{
}

fn main() {
    let rt = tokio::runtime::Builder::new_multi_thread().build().unwrap();

    closure(move |ctx: Context| {
        rt.spawn(async {
            let a = ctx;
        });
    });
}

Playground.


  1. Or some other thread-safe alternative, like an Arc . ↩︎

4 Likes

Thank U for your answer. I have tried Arc and other thread-safe operations, but still got the error.

This is just a Demo, In my scenario, it must be a raw pointer.

image

Consider copy that pointer?

pub struct Context {
  raw: *mut String,
}

A pointer is small and is suitable for copying. You can treat it as usize.
If You need that pointer to be mutable, consider

use std::sync::atomic::AtomicPtr;

pub struct Context {
  raw: Arc<AtomicPtr<String>>,
}

Generally whether you need that pointer to be mutable or not, Context must be 'static. Consider using Arc and AtomicPtr to solve this problem.

The reason is Rust, even the operate system cannot be sure in two thread which one exits first without additional guarantee. So only struct whose validation must not affected by other thread can be sent through threads, that is what 'static partly means.

1 Like

The problem here isn't the raw pointer sys::napi_value, it's the two &'env ... fields. Try a definition like this instead:

pub struct CallContext {
    pub env: Arc<RwLock<Env>>,
    raw_this: sys::napi_value,
    callback_info: sys::napi_callback_info,
    args: Vec<sys::napi_value>,
}

impl CallContext {
    pub fn len(&self)->usize { self.args.len() }
}
3 Likes

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.