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