2个不稳定版本
0.2.0 | 2020年5月11日 |
---|---|
0.1.0 | 2019年1月17日 |
#1704 in Rust模式
7,858 每月下载量
用于 11 个crate(3个直接使用)
8KB
60 行
问题
让我们考虑以下代码
use once_cell::sync::OnceCell;
trait X{
fn string() -> String;
}
// having to recompute string() over and over might be expensive (not in this example, but still)
// so we use lazy initialization
fn generic<T: X>() -> &'static str{
static VALUE: OnceCell<String> = OnceCell::new();
VALUE.get_or_init(||{
T::string()
})
}
// And now it can be used like this
struct A;
impl X for A{
fn string() -> String{
"A".to_string()
}
}
struct B;
impl X for B{
fn string() -> String{
"B".to_string()
}
}
fn main(){
assert_eq!(generic::<A>(), "A");
assert_eq!(generic::<B>(), "A"); // Wait what?
// Not completely behaviour I was expecting
// This is due to fact that static variable placed inside of generic function
// wont be cloned into each version of function, but will be shared
// Thus second call does not initialize value for B, but takes value
// initialized in previous call.
}
解决方案
该crate旨在解决这个特定问题。
让我们做一些修改
use generic_static::StaticTypeMap;
use once_cell::sync::OnceCell;
trait X{
fn string() -> String;
}
// having to recompute string() over and over might be expensive (not in this example, but still)
// so we use lazy initialization
fn generic<T: X + 'static>() -> &'static str{ // T is bound to 'static
static VALUE: OnceCell<StaticTypeMap<String>> = OnceCell::new();
let map = VALUE.get_or_init(|| StaticTypeMap::new());
map.call_once::<T, _>(||{
T::string()
})
}
// And now it can be used like this
struct A;
impl X for A{
fn string() -> String{
"A".to_string()
}
}
struct B;
impl X for B{
fn string() -> String{
"B".to_string()
}
}
fn main(){
assert_eq!(generic::<A>(), "A");
assert_eq!(generic::<B>(), "B");
}
缺点
当前实现使用RwLock使其在并发应用程序中更安全,这会比常规慢一点
依赖
~48KB