实现思路
- 使用
OnceCell
来确保资源只被初始化一次。
- 由于初始化可能失败,
OnceCell
中存储的类型应该是 Result<T, E>
,其中 T
是资源类型,E
是错误类型。
- 对于异步初始化操作,可以使用
async
/await
语法,并结合 OnceCell
提供的 get_or_try_init
方法来处理。
- 可以通过
Mutex
来保护 OnceCell
,以确保在多线程环境下的线程安全。
代码框架(以Rust为例)
use std::cell::OnceCell;
use std::sync::{Arc, Mutex};
use tokio::sync::Mutex as AsyncMutex;
// 假设这是你的资源类型
struct MyResource {
// 这里存放从数据库加载的配置信息等
config: Vec<String>,
}
// 假设这是初始化时可能发生的错误类型
#[derive(Debug)]
struct InitError;
// 创建一个全局的OnceCell来存储资源
static RESOURCE: OnceCell<Result<Arc<AsyncMutex<MyResource>>, InitError>> = OnceCell::new();
// 初始化资源的异步函数
async fn init_resource() -> Result<Arc<AsyncMutex<MyResource>>, InitError> {
// 模拟从数据库加载配置信息的异步操作
let config = load_config_from_db().await.map_err(|_| InitError)?;
let resource = MyResource { config };
Ok(Arc::new(AsyncMutex::new(resource)))
}
// 模拟从数据库加载配置信息的异步函数
async fn load_config_from_db() -> Result<Vec<String>, ()> {
// 实际实现中应该包含数据库操作逻辑
Ok(vec!["config1".to_string(), "config2".to_string()])
}
// 获取资源的函数
async fn get_resource() -> Result<Arc<AsyncMutex<MyResource>>, InitError> {
let guard = RESOURCE.get_or_try_init(|| async {
init_resource().await
}).await?;
Ok(guard.clone())
}