#map #container #any

no-std anymap3

为每种类型提供一个安全且便捷的存储空间

1个稳定版本

1.0.0 2024年1月1日

#865 in Rust模式

Download history 63/week @ 2024-04-14 347/week @ 2024-04-21 206/week @ 2024-04-28 82/week @ 2024-05-05 69/week @ 2024-05-12 175/week @ 2024-05-19 298/week @ 2024-05-26 466/week @ 2024-06-02 878/week @ 2024-06-09 1271/week @ 2024-06-16 1051/week @ 2024-06-23 1493/week @ 2024-06-30 1528/week @ 2024-07-07 1054/week @ 2024-07-14 1098/week @ 2024-07-21 551/week @ 2024-07-28

4,266每月下载量
用于 aerosol

BlueOak-1.0.0 OR MIT OR Apache-2.0

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

特性

  • 在一个包中为每种类型存储一个值。
  • 添加 SendSend + Sync 边界。
  • 您可以选择启用创建地图的 Clone 功能。 (从理论上讲,您可以添加各种其他功能,但是您无法轻松地通用化实现,其基本结构足够简单,因此最好创建自己的 Any 扩展并重新实现 AnyMap。)
  • 如果您喜欢,可以使用 no_std。

Cargo 功能/依赖/使用方法

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

[dependencies]
anymap3 = "1.0.0"

无 std 使用,提供由 allochashbrown 包支持的 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 + Senddyn CloneAny + Send + SyncClone 实现,使用不安全代码来附加自动 traits,以避免使用安全代码时的 虚假的未来兼容性 lint

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

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

后记

作者: Chris Morgan 是此库的作者。

分支维护者:Olivier 'reivilibre' 是此分支的维护者。

许可协议:本库根据您的选择,在以下协议下分发:蓝橡模型许可协议 1.0.0MIT 许可协议Apache 许可协议 2.0 版。详细信息请参阅 COPYING

依赖项

~0–315KB