Rust模式:使用Box::leak創(chuàng)建一個&'static引用
假設你有這個Config結構體,它在程序啟動時加載一次,然后在整個生命周期中都是不可變的。
問題是,Config需要被程序的許多部分訪問:
struct UsersService {
config: Config,
}
struct OrdersService {
config: Config,
}
// ...
let config = config::load()?;
let users_service = UsersService::new(config.clone());
let orders_service = OrdersService::new(config.clone());
在上面的代碼中,Config被嵌入到兩個結構體中,這可能不是理想的,因為這兩個結構體將隨著Config的大小而增長,而它們可能只需要訪問1或2個字段。
一個好的選擇是使用智能指針:Rc或Arc,這樣我們就可以共享Config的引用。因為我們的程序是多線程的(就像現在的大多數程序一樣),我們將使用Arc指針,這樣我們的結構就可以在線程之間發(fā)送:
struct UsersService {
config: Arc<Config>,
}
struct OrdersService {
config: Arc<Config>,
}
// ...
let config = Arc::new(config::load()?);
let users_service = UsersService::new(config.clone());
let orders_service = OrdersService::new(config.clone());
這里,UsersService和OrdersService只嵌入了一個Arc指針,這只增加了8個字節(jié)。
是否能做得更好呢?對于在程序的整個生命周期中都是不可變的數據,最好使用&'static引用。
但是如何創(chuàng)建&'static引用的Config,在運行時加載?
請使用Box::leak,它在堆上分配內部結構體(這里是Config),并將引用“泄漏”到'static的生命周期。
struct UsersService {
config: Arc<Config>,
}
struct OrdersService {
config: Arc<Config>,
}
// ...
let config = Arc::new(config::load()?);
let users_service = UsersService::new(config.clone());
let orders_service = OrdersService::new(config.clone());
代碼仍然與我們的原始代碼非常相似,但是現在我們的UsersService和OrdersService只嵌入一個指針大小的引用,并且運行時開銷正好為0。