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 数据结构

Download history 4/week @ 2024-03-26 28/week @ 2024-04-02 3/week @ 2024-04-23 2/week @ 2024-04-30 14/week @ 2024-05-07 16/week @ 2024-05-14 4/week @ 2024-05-28

436 每月下载量
用于 transit_model

MIT 许可证

17KB
189

GitHub Action Status Latest Version

relational_types

对象之间关系的建模。有关更多信息,请参阅文档


lib.rs:

对象之间关系的建模。

默认情况下,启用了功能 relational_types_procmacro,公开宏以帮助构建关系。有关更多信息,请参阅 relational_types_procmacro 的文档。

此模块定义了用于建模对象之间关系的类型,并通过 GetCorresponding 自定义 derive 使用它们。

让我们用一个例子来澄清这一点。假设 Bike 有一个 BrandBike 也有一个 Owner,而这些 Owner 有一个 JobBike 也有一个 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>BikeBrand 之间的关系。使用所有关系,它生成一个图,计算所有类型之间的最短路径,并为每条可行路径生成 impl GetCorresponding

这些 impl GetCorresponding 被用于 World::get_corresponding_from_idxWorld::get_corresponding,它们是用于探索 World 的辅助函数。

因此,当我们为 Owner 调用 world.get_corresponding_from_idx(mbk) 时,我们将使用生成的代码,该代码基本上获取所有与品牌 MBK 对应的 Bike,然后获取与这些 Bike 对应的所有 Owner

想象一下,在我们的应用中,我们经常使用 Owner->KindBrand->Kind 搜索。为了执行这些搜索,我们通过 Bike 进行,我们的模型中有大量的 Bike。因此,作为一个优化,我们希望预先计算这些关系。

Brand - Bike - Owner - Job
   \     |      /
    `-- Kind --'

快捷方式 Brand - KindKind - Owner 允许我们的优化,但现在我们面临一个 Owner->Brand 搜索的问题:我们可以通过 Owner->Kind->BrandOwner->Bike->Brand 以 2 的成本完成。第一种解决方案显然是错误的,是由我们的快捷方式引入的。为了解决这个问题,我们可以给 Brand - KindKind - 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