4 个稳定版本
| 2.0.0 | 2021 年 5 月 6 日 |
|---|---|
| 1.1.0 | 2021 年 4 月 19 日 |
| 1.0.1 | 2020 年 4 月 24 日 |
| 1.0.0 | 2020 年 3 月 27 日 |
#1173 in 数据结构
436 每月下载量
用于 transit_model
17KB
189 行
relational_types
对象之间关系的建模。有关更多信息,请参阅文档。
lib.rs:
对象之间关系的建模。
默认情况下,启用了功能 relational_types_procmacro,公开宏以帮助构建关系。有关更多信息,请参阅 relational_types_procmacro 的文档。
此模块定义了用于建模对象之间关系的类型,并通过 GetCorresponding 自定义 derive 使用它们。
让我们用一个例子来澄清这一点。假设 Bike 有一个 Brand。 Bike 也有一个 Owner,而这些 Owner 有一个 Job。 Bike 也有一个 Kind。
Brand - Bike - Owner - Job
|
Kind
让我们定义这些关系并使用它们
#[derive(Default, GetCorresponding)]
pub struct World {
brands_to_bikes: OneToMany<Brand, Bike>,
owners_to_bikes: OneToMany<Owner, Bike>,
jobs_to_owners: OneToMany<Job, Owner>,
kinds_to_bikes: OneToMany<Kind, Bike>,
}
let world = World::default();
let mbk: Idx<Brand> = get_mbk_brand();
let owners_with_mbk: IdxSet<Owner> = world.get_corresponding_from_idx(mbk);
let jobs_with_mbk: IdxSet<Job> = world.get_corresponding(&owners_with_mbk);
println!(
"{} owners with {} different jobs own a bike of the brand MBK.",
owners_with_mbk.len(),
jobs_with_mbk.len()
);
首先,我们想要建模对象之间的关系。一辆自行车有一个品牌,一个品牌有多个自行车(希望如此)。因此,我们使用 OneToMany<Bike, Brand> 来建模这种关系。
我们重复此过程以建模每个关系。我们不太费力地获得 World 结构。
GetCorresponding derive 查看每个 World 结构的字段,保留包含 _to_ 且具有 2 个泛型的类型的字段,并将其解释为关系。例如,bikes_to_brands: OneToMany<Bike, Brand> 是 Bike 和 Brand 之间的关系。使用所有关系,它生成一个图,计算所有类型之间的最短路径,并为每条可行路径生成 impl GetCorresponding。
这些 impl GetCorresponding 被用于 World::get_corresponding_from_idx 和 World::get_corresponding,它们是用于探索 World 的辅助函数。
因此,当我们为 Owner 调用 world.get_corresponding_from_idx(mbk) 时,我们将使用生成的代码,该代码基本上获取所有与品牌 MBK 对应的 Bike,然后获取与这些 Bike 对应的所有 Owner。
想象一下,在我们的应用中,我们经常使用 Owner->Kind 和 Brand->Kind 搜索。为了执行这些搜索,我们通过 Bike 进行,我们的模型中有大量的 Bike。因此,作为一个优化,我们希望预先计算这些关系。
Brand - Bike - Owner - Job
\ | /
`-- Kind --'
快捷方式 Brand - Kind 和 Kind - Owner 允许我们的优化,但现在我们面临一个 Owner->Brand 搜索的问题:我们可以通过 Owner->Kind->Brand 和 Owner->Bike->Brand 以 2 的成本完成。第一种解决方案显然是错误的,是由我们的快捷方式引入的。为了解决这个问题,我们可以给 Brand - Kind 和 Kind - Owner 赋予权重 1.9。现在 Owner->Kind->Brand 的成本是 3.8,并且被丢弃。
让我们来实现这个
#[derive(GetCorresponding)]
pub struct World {
brands_to_bikes: OneToMany<Brand, Bike>,
owners_to_bikes: OneToMany<Owner, Bike>,
jobs_to_owners: OneToMany<Job, Owner>,
kinds_to_bikes: OneToMany<Kind, Bike>,
// shortcuts
#[get_corresponding(weight = "1.9")]
brands_to_kinds: ManyToMany<Brand, Kind>,
#[get_corresponding(weight = "1.9")]
kinds_to_owners: ManyToMany<Kind, Owner>,
}
impl World {
fn new() -> World {
let brands_to_bikes = create_brands_to_bikes();
let owners_to_bikes = create_owners_to_bikes();
let jobs_to_owners = create_jobs_to_owners();
let kinds_to_bikes = create_kinds_to_bikes();
World {
brands_to_kinds: ManyToMany::from_relations_sink(
&brands_to_bikes,
&kinds_to_bikes,
),
kinds_to_owners: ManyToMany::from_relations_sink(
&kinds_to_bikes,
&owners_to_bikes,
),
brands_to_bikes,
owners_to_bikes,
jobs_to_owners,
kinds_to_bikes,
}
}
}
依赖项
~0.9–1.6MB
~33K SLoC