1

我的问题如下:


是否可以对对象进行延迟初始化,然后将其借用为'static终生可变的?


一些上下文

首先,我将展示一个示例来说明延迟初始化的含义。我提出的延迟初始化模型是将 cratelazy_static与一个标准库一起使用,其中包含Mutex一个Option<T>. 这里有一个延迟初始化的例子。

use lazy_static::lazy_static;

use std::thread::JoinHandle;
use std::sync::Mutex;

pub struct DeferredStruct {
    internal_field: u32,
}

impl DeferredStruct {
    pub fn new(internal_field: u32) -> Self {
        Self {
            internal_field,
        }
    }

    pub fn regular_function(&mut self) {
        self.internal_field += 1;
        println!("{}", self.internal_field);
    }
}

lazy_static! {
    static ref MY_DEFERRED: Mutex<Option<DeferredStruct>> = Mutex::new(None);
}

fn main() {
    // Initial processing
    // ...
    // ...
    
    // The value 10 would be obtained from a configuration file on runtime.
    let deferred_struct = DeferredStruct::new(10);
    let mut lock = MY_DEFERRED.lock().unwrap();  
    lock.replace(deferred_struct);
    std::mem::drop(lock); // In this example we drop the lock to avoid a deadlock when calling another_function.
    // More processing
    // ...
    // ...
    let thread_handle = another_function();
    thread_handle.join().unwrap();
}

// From another part of the program and possibly from another thread we
// lock MY_DEFERRED and call regular_funcion on it.
fn another_function() -> JoinHandle<()> {
    std::thread::spawn(|| {
        let mut lock = MY_DEFERRED.lock().unwrap();
        if let Some(deferred) = lock.as_mut() {
            deferred.regular_function();
        } 
    })
}

您可以在Rust Playground中执行上述代码并检查它11是否正确打印。

引入需要静态生命周期的结构函数

现在,假设我在其中添加了一个函数,该函数DeferredStruct将创建一个工作线程以执行一些需要很长时间的计算:

pub struct DeferredStruct {
    internal_field: u32,
}

impl DeferredStruct {
    pub fn new(internal_field: u32) -> Self {
        Self {
            internal_field,
        }
    }

    pub fn regular_function(&mut self) {
        self.internal_field += 1;
        println!("{}", self.internal_field);
    }

    pub fn static_function(&'static mut self) {
        std::thread::spawn(move || {
            // Do something really long.
            // Finally I make some changes on self
            self.internal_field += 100;
        });
    }
}

在这种情况下,需要&mut self有一个'static生命周期:

error[E0759]: `self` has an anonymous lifetime `'_` but it needs to satisfy a `'static` lifetime requirement.

因此,该函数将采用&'static mut self.

当试图借用as和的DeferredStruct内部Option时,问题就来了。MY_DEFERRED'staticmut

如果我不能借钱'staticmut那么我不能打电话deferred.static_function()。因为价值不会存在足够长的时间。

error[E0597]: `lock` does not live long enough
  --> src/main.rs:57:33
   |
57 |         if let Some(deferred) = lock.as_mut() {
   |                                 ^^^^---------
   |                                 |
   |                                 borrowed value does not live long enough
   |                                 argument requires that `lock` is borrowed for `'static`
...
60 |     })
   |     - `lock` dropped here while still borrowed

这里有一个Rust Playground中的最小可重现示例。

TL;博士

是否可以借用在运行时创建的对象(不一定是在程序的立即启动时创建的)在 aMutex<Option<T>>中作为可变对象并'static终身使用?

任何帮助表示赞赏。

4

0 回答 0