1个稳定版本
1.0.0 | 2024年1月1日 |
---|
#865 in Rust模式
4,266每月下载量
用于 aerosol
41KB
483 行
AnyMap
,为每种类型提供一个安全且便捷的存储空间
AnyMap
是一个类型安全的包装器,围绕 HashMap<TypeId, Box<dyn Any>>
,让你不必担心 TypeId
或向下转换,只需存储一袋各种类型中的一个,这对于某些库的扩展性非常有用。
背景
如果你熟悉Go和Go网络框架,你可能已经遇到了用于存储与请求相关的数据的常见“环境”模式。通常是这样的 map[string]interface{},并通过任意字符串访问,可能存在冲突,类型断言稍微难以操作,并且必须非常小心地使用。(我个人认为这简直是在 请求 灾难发生。)在像Go这样的缺乏泛型的语言中,这是能做到的最好的方法;没有泛型,这种事情不可能变得安全。
作为此类接口的另一个例子,JavaScript对象正好相同——字符串键到任意值的映射。(在那里实际上 更 危险,因为方法和字段/属性/属性在同一个层面上——尽管现在 可以使用 Map
。)
幸运的是,在Rust中我们可以做得更好。我们的类型系统非常适合轻松、健壮地表达此类问题。
示例
let mut data = anymap3::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
支持的 anymap3::AnyMap
等。
[dependencies]
anymap3 = "1.0.0"
无 std 使用,提供由 alloc
和 hashbrown 包支持的 anymap3::hashbrown::AnyMap
等。 (注意路径不同,这是由于 Cargo 功能是累积的所必需的)
[dependencies]
anymap3 = { version = "1.0.0", 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
实现,使用不安全代码来附加自动 traits,以避免使用安全代码时的 虚假的未来兼容性 lint。 -
出于性能考虑,由于数据结构的性质,跳过了类型 ID 检查,因为它们是不必要的(尽管这确实是以将
Map::{as_raw_mut, into_raw}
标记为不安全为代价的)。
可以移除所有不安全代码,但代价是仅保留 CloneAny
功能和一点性能。Git 仓库中的 safe
分支包含几个提交,展示了这一概念。这非常简单;此库的核心非常简单且完全安全。
后记
作者: Chris Morgan 是此库的作者。
分支维护者:Olivier 'reivilibre' 是此分支的维护者。
许可协议:本库根据您的选择,在以下协议下分发:蓝橡模型许可协议 1.0.0、MIT 许可协议 和 Apache 许可协议 2.0 版。详细信息请参阅 COPYING。
依赖项
~0–315KB