21个版本
1.0.0-beta.2 | 2022年2月22日 |
---|---|
0.12.1 | 2017年1月20日 |
0.12.0 | 2016年3月5日 |
0.11.1 | 2015年6月24日 |
0.9.2 | 2014年11月28日 |
2294 in Rust模式
74,187 每月下载量
在 227 个crate中使用 (54 直接使用)
40KB
466 行
AnyMap
,为每种类型存储一个值的安全便捷存储
AnyMap
是 HashMap<TypeId, Box<dyn Any>>
的类型安全包装,允许您无需担心 TypeId
或向下转换,只需存储不同类型的每个值,这在某些类型的库的扩展性方面非常有用。
背景
如果您熟悉Go和Go Web框架,您可能遇到过用于存储与请求相关数据的常见“环境”模式。它通常是类似于 map[string]interface{}
的东西,并且使用任意的字符串进行访问,这些字符串可能会冲突,类型断言也有些难以控制,并且必须非常小心地使用。(我个人认为这简直就是 自找麻烦。)在Go这样的语言中,由于缺乏泛型,这已经是最接近的方法;没有泛型,这种事情不可能做到安全。
作为此类接口的另一个示例,JavaScript对象完全相同——字符串键到任意值的映射。(在那里它实际上更危险,因为方法和字段/属性/属性处于同一层面——尽管现在可以使用 Map
。)
幸运的是,在Rust中我们可以做得比这些更好。我们的类型系统非常适合轻松、稳健地表达此类问题。
示例
let mut data = anymap::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 {
str: String,
}
assert_eq!(data.get::<Foo>(), None);
data.insert(Foo { str: format!("foo") });
assert_eq!(data.get(), Some(&Foo { str: format!("foo") }));
data.get_mut::<Foo>().map(|foo| foo.str.push('t'));
assert_eq!(&*data.get::<Foo>().unwrap().str, "foot");
特性
- 在一个包中存储每种类型的一个值。
- 添加
Send
或Send + Sync
边界。 - 您可以选择启用制作地图
Clone
。 (从理论上讲,您可以添加各种其他功能,但是您不能轻易地使其泛化,而且它的基础足够简单,最好是扩展Any
并重新实现AnyMap
。) - 如果您喜欢,请使用 no_std。
Cargo 功能/依赖/使用
典型的 Cargo.toml 使用方式,提供由 std::collections::HashMap
支持的 anymap::AnyMap
等等。
[dependencies]
anymap = "1.0.0-beta.2"
无 std 使用,提供由 alloc
和 hashbrown crate 支持的 anymap::hashbrown::AnyMap
等等。(注意路径不同,因为 Cargo 功能是累加的)
[dependencies]
anymap = { version = "1.0.0-beta.2", default-features = false, features = ["hashbrown"] }
关于稳定性: hashbrown 仍处于 1.0.0 预发布版本,并经历着破坏性变更。因为它对一小部分用户有用,所以我保留了它,但与典型的 SemVer 兼容性保证不同。尽可能的,我会在 hashbrown 的新版本中扩大兼容范围,但如果发生不兼容的变更,我可能会通过将 anymap 版本的次要部分提升来放弃对 hashbrown 旧版本的支持(例如 1.1.0、1.2.0)。如果您使用此功能,这是您考虑使用类似 "~1.0"
(或将其展开为 >=1, <1.1
)的要求的原因。
此库中的不安全代码
此库使用大量不安全代码,原因有几个。
-
为了支持
CloneAny
,目前需要不安全代码(因为向下转换方法是在dyn Any
上定义的,而不是作为 trait 方法,并且向上转换是 rustc 中的不完整功能);如果您想要放弃Clone
支持,则可以移除这种不安全性。 -
对于
dyn CloneAny + Send
和dyn CloneAny + Send + Sync
的Clone
实现使用不安全块将自动特征附加到原本使用安全代码的地方,以避免一个 虚假的将来兼容性 lint。 -
出于性能考虑,由于数据结构的不变性,类型 ID 检查被跳过,因为它们是不必要的(尽管这确实会以
Map::{as_raw_mut, into_raw}
被标记为不安全为代价)。
可以通过仅以 CloneAny
功能和一点点性能为代价来移除所有不安全代码。Git 仓库中的 safe
分支包含一些提交,展示了这个概念。这非常简单;这个库的核心非常简单且完全安全。
致谢
作者: Chris Morgan 是此库的作者和维护者。
许可证: 此库根据您选择的条款进行分发,包括 Blue Oak Model License 1.0.0、MIT 许可证 和 Apache 许可证 2.0 版。详细信息请参阅 COPYING。
依赖关系
~0–315KB