2个不稳定版本

0.2.0 2020年5月11日
0.1.0 2019年1月17日

#1704 in Rust模式

Download history 1116/week @ 2024-01-18 1611/week @ 2024-01-25 979/week @ 2024-02-01 972/week @ 2024-02-08 1083/week @ 2024-02-15 1012/week @ 2024-02-22 888/week @ 2024-02-29 1340/week @ 2024-03-07 1322/week @ 2024-03-14 1147/week @ 2024-03-21 1567/week @ 2024-03-28 1382/week @ 2024-04-04 3082/week @ 2024-04-11 2158/week @ 2024-04-18 1288/week @ 2024-04-25 1042/week @ 2024-05-02

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