1 个不稳定版本
0.13.0 | 2021年4月10日 |
---|
1031 在 数据结构 中排名
115,982 每月下载量
在 219 个crate(13 个直接) 中使用
43KB
781 行
🗺️ AnyMap
存储零个或一个每种类型的映射。
AnyMap
是一个围绕 HashMap<TypeId, Box<Any>>
的包装器,暴露一个类型安全的、健壮的接口。
分开的 CloneAny*
特性意味着在映射中的所有类型上强制执行额外的 Send
/ Sync
约束,这是从 anymap
crate 中的用户体验损失。这是避免以下警告的方法: https://github.com/rust-lang/rust/issues/51443
注意: 这是 anymap
的一个分支,具有额外的约束,即如果映射中的任何类型需要是 Send
或 Sync
或两者,则映射中的所有类型都具有该约束。当上述Rust问题修复后,这个分支应该消失。我只是创建它,以免更新Rust意外破坏映射功能。
用法
将以下内容添加到 Cargo.toml
anymap2 = "0.13.0"
代码
use anymap2::AnyMap; // Map<dyn Any>
let mut data = AnyMap::new();
assert_eq!(data.get(), None::<&i32>);
data.insert(42i32);
assert_eq!(data.get(), Some(&42i32));
data.remove::<i32>();
assert_eq!(data.get::<i32>(), None);
#[derive(Clone, PartialEq, Debug)]
struct Foo {
value: String,
}
assert_eq!(data.get::<Foo>(), None);
data.insert(Foo {
value: format!("foo"),
});
assert_eq!(
data.get(),
Some(&Foo {
value: format!("foo")
})
);
data.get_mut::<Foo>().map(|foo| foo.value.push('t'));
assert_eq!(&*data.get::<Foo>().unwrap().value, "foot");
unsafe
代码
此库出于多个原因使用了大量不安全代码
-
为了支持
Any
和CloneAny
,需要使用unsafe
代码(因为downcast
方法是在impl Any
中定义的,而不是作为 trait 方法;我认为这是std::any::Any
结构的历史细节);如果您想放弃Clone
支持,则可以移除这种不安全性。 -
出于性能考虑,跳过因数据结构的不变性而无需进行的各种检查(当它被用作哈希表键时,不需要检查类型 ID)并简化哈希(类型 ID 已经是很好的哈希值,无需通过 SipHash 对其进行篡改)。
在不移除一些功能的情况下,无法从这个库中完全移除所有不安全性。不过,以牺牲 CloneAny
功能以及原始接口和可能的后台支持为代价,您肯定可以移除所有 unsafe
代码。以下是您如何做到这一点:
- 移除其泛型性;
- 将
anymap::raw
合并到正常接口中,使其扁平化; - 将类似
.map(|any| unsafe { any.downcast_unchecked() })
的代码更改为.and_then(|any| any.downcast())
(性能成本:一个额外的多余类型 ID 比较和间接比较); - 丢弃
TypeIdHasher
,因为类型 ID 的转换是不允许的(成本:每次访问都进行 SIP 篡改 u64)。
是的,安全性的性能成本相当小。更严重的问题是失去了 Clone
以及可能 Send + Sync
。
但坦白说,如果您想完成所有这些工作,从头开始编写会更简单、更快。实际上,库的核心非常简单且完全安全,如第一个提交中的 src/lib.rs
(请注意,该代码需要进行一些语法更改才能运行;它在 Rust 1.0 之前编写,有一些像 Any:'static
这样的代码,而现在我们有 Any + 'static
)。
作者
Chris Morgan (chris-morgan) 是 AnyMap 的主要作者和维护者。
许可证
此库与 Rust 的条款类似:MIT 许可证和 Apache 许可证(版本 2.0)的双重许可。
有关详细信息,请参阅 LICENSE-APACHE、LICENSE-MIT 和 COPYRIGHT。