5 个版本
0.2.3 | 2023年6月29日 |
---|---|
0.2.2 | 2023年6月26日 |
0.2.1 | 2023年6月25日 |
0.2.0 | 2023年6月25日 |
0.1.0 | 2023年6月21日 |
在 #deterministic 中排名第 65
每月下载量 94
用于 certain-map
25KB
481 行
特定映射
一种确保元素存在的类型化映射。
解决的问题
在 Rust 中,我们经常使用服务抽象进行模块化结构设计(例如 tower-service 或 service-async)。
服务是堆叠的,不同层的请求/响应类型可能不同。
当不同层的组件存在数据依赖关系时,尤其是间接依赖关系,通过更改请求/响应类型来传递所有所需信息变得很困难。
当需要传递的变量数量增加或减少时,我们必须重新定义一个结构来加载这些数量,并且需要为这些结构实现转换函数和数据提取函数。这将是一项巨大而枯燥的工作,并且会使代码变得杂乱。
因此,我们通常不这样做,我们经常使用 HashMap 或 TypeMap 来管理需要在服务之间传递的信息。
但这将带来一个明显的问题:我们无法在编译时确保在读取时所需的键值已经被设置。这可能导致我们程序中的不合理错误处理分支或在某些场景中发生 panic。
优点
在这个crate中,我们在插入或删除键时转换结构类型。因此,我们可以确保某些值在编译时必须存在。
当您需要使用结构在多个阶段之间传递信息时,这个crate将非常适合您。
这再次实现了承诺:如果编译成功,则它将工作。
使用方法
use certain_map::{certain_map, Param, ParamRef, ParamRemove, ParamSet, ParamTake};
struct UserName(String);
#[derive(Copy, Clone)]
struct UserAge(u8);
certain_map! {
pub struct MyCertainMap {
name: UserName,
#[ensure(Clone)]
age: UserAge,
}
}
fn main() {
let meta = MyCertainMap::new();
// The following line compiles fail since there's no UserName in the map.
// log_username(&meta);
let meta = meta.param_set(UserName("ihciah".to_string()));
// Now we can get it with certainty.
log_username(&meta);
let (meta, removed) = ParamTake::<UserName>::param_take(meta);
assert_eq!(removed.0, "ihciah");
// The following line compiles fail since the UserName is removed.
// log_username(&meta);
// We can also remove a type no matter if it exist.
let meta = ParamRemove::<UserName>::param_remove(meta);
let meta = meta.param_set(UserAge(24));
// we can get ownership of fields with #[ensure(Clone)]
log_age(&meta);
}
fn log_username<T: ParamRef<UserName>>(meta: &T) {
println!("username: {}", meta.param_ref().0);
}
fn log_age<T: Param<UserAge>>(meta: &T) {
println!("user age: {}", meta.param().0);
}
依赖
~290–750KB
~18K SLoC