#container #map #key-value-store #any

未维护 无std anymap

为每种类型存储一个值的安全便捷存储

21个版本

1.0.0-beta.22022年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模式

Download history 30918/week @ 2024-03-14 27131/week @ 2024-03-21 19067/week @ 2024-03-28 17371/week @ 2024-04-04 19267/week @ 2024-04-11 19097/week @ 2024-04-18 16732/week @ 2024-04-25 15779/week @ 2024-05-02 18014/week @ 2024-05-09 18071/week @ 2024-05-16 15468/week @ 2024-05-23 20385/week @ 2024-05-30 17920/week @ 2024-06-06 19367/week @ 2024-06-13 20092/week @ 2024-06-20 12749/week @ 2024-06-27

74,187 每月下载量
227 个crate中使用 (54 直接使用)

BlueOak-1.0.0 OR MIT OR Apache-2.0

40KB
466

AnyMap,为每种类型存储一个值的安全便捷存储

AnyMapHashMap<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");

特性

  • 在一个包中存储每种类型的一个值。
  • 添加 SendSend + Sync 边界。
  • 您可以选择启用制作地图 Clone。 (从理论上讲,您可以添加各种其他功能,但是您不能轻易地使其泛化,而且它的基础足够简单,最好是扩展 Any 并重新实现 AnyMap。)
  • 如果您喜欢,请使用 no_std。

Cargo 功能/依赖/使用

典型的 Cargo.toml 使用方式,提供由 std::collections::HashMap 支持的 anymap::AnyMap 等等。

[dependencies]
anymap = "1.0.0-beta.2"

无 std 使用,提供由 allochashbrown 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 + Senddyn CloneAny + Send + SyncClone 实现使用不安全块将自动特征附加到原本使用安全代码的地方,以避免一个 虚假的将来兼容性 lint

  • 出于性能考虑,由于数据结构的不变性,类型 ID 检查被跳过,因为它们是不必要的(尽管这确实会以 Map::{as_raw_mut, into_raw} 被标记为不安全为代价)。

可以通过仅以 CloneAny 功能和一点点性能为代价来移除所有不安全代码。Git 仓库中的 safe 分支包含一些提交,展示了这个概念。这非常简单;这个库的核心非常简单且完全安全。

致谢

作者: Chris Morgan 是此库的作者和维护者。

许可证: 此库根据您选择的条款进行分发,包括 Blue Oak Model License 1.0.0MIT 许可证Apache 许可证 2.0 版。详细信息请参阅 COPYING

依赖关系

~0–315KB