2 个版本

0.1.1 2022年2月15日
0.1.0 2021年10月29日

#1707Rust 模式

MIT 许可证

8KB

haz

对多态环境的薄抽象。

github crates.io docs.rs build status

动机

考虑一个场景,我们想要将一些数据传递给几个函数。

也许我们有一个类型 Config 来表示我们应用程序的配置,它包含一系列数据(例如 HostPortVerbosityRestriction 以及可能还有许多其他字段)

struct Config {
  host: Host,
  port: Port,
  verbosity: Verbosity,
  restriction: Restriction,
  // ...
}

我们可能想要将这些数据传递给一些函数,然后这些函数将使用相关的字段来执行一些操作

fn do_something_with_host_port_verbosity(...) {
  // ...
}

// ...

我们可以将整个 Config 的引用传递给每个函数

fn do_something_with_host_port_verbosity(cfg: &Config) {
  //...
}

// ...

但是,并不是每个函数都需要知道每个字段,我们可能想要避免这种不必要的耦合。

一种方法是为每个需要这些字段的函数显式地传递每个字段

fn do_something_with_host_port_verbosity(host: &Host, port: &Port, restriction: &Restriction) {
  // ...
}

// ...

然而,在使用位置可能比较繁琐,因为我们需要逐个传递每个字段

let cfg = read_config();
do_something_with_host_port_verbosity(&cfg.host, &cfg.port, &cfg.verbosity);

我需要数据吗?

haz 的想法是帮助实现这两个目标

  • 不要向不需要访问这些数据的函数传递数据
  • 不需要逐个传递每个字段

一切围绕薄特质 Has<Component> 浮动

trait Has<Component> {
    fn access(&self) -> &Component;
}

通过为某些类型 Container 实现 Has<Component>,我们声明 Container 可以提供对 Component 的只读访问。

有了这个特质,假设我们已经为 Config 实现了 Has<Host>Has<Port>Has<Verbosity> 等等(可能使用 impl_has_for_named_component)的实现,我们可以利用它作为

fn do_something_with_host_port_verbosity<C>(cfg: &C)
where
  C: Has<Host> + Has<Port> + Has<Verbosity> {
  //...
}

// ...

我们已经明确声明了我们作为 do_something_with_host_port_verbosity 需要什么,因此将获得访问权限——但不是其他任何东西。

在用法位置,它将看起来像

let cfg = read_config();
do_something_with_host_port_verbosity(&cfg);

我们只是传递对 Config 的引用,而不是逐个字段。

总之,我们已经实现了我们的两个目标

  • 不要向不需要访问这些数据的函数传递数据
  • 不需要逐个传递每个字段

无运行时依赖