generics - 如何避免将具体结构更改为通用结构所产生的链式 react ?

标签 generics rust traits

我有一个如下所示的配置结构:

struct Conf {
    list: Vec<String>,
}

该实现在内部填充了 list 成员,但现在我决定将该任务委托(delegate)给另一个对象。所以我有:

trait ListBuilder {
    fn build(&self, list: &mut Vec<String>);
}

struct Conf<T: Sized + ListBuilder> {
    list: Vec<String>,
    builder: T,
}

impl<T> Conf<T>
where
    T: Sized + ListBuilder,
{
    fn init(&mut self) {
        self.builder.build(&mut self.list);
    }
}

impl<T> Conf<T>
where
    T: Sized + ListBuilder,
{
    pub fn new(lb: T) -> Self {
        let mut c = Conf {
            list: vec![],
            builder: lb,
        };
        c.init();
        c
    }
}

这似乎工作正常,但现在到处我使用Conf,我必须改变它:

fn do_something(c: &Conf) {
    // ...
}

成为

fn do_something<T>(c: &Conf<T>)
where
    T: ListBuilder,
{
    // ...
}

由于我有很多这样的函数,这种转换很痛苦,尤其是因为 Conf 类的大多数用法并不关心 ListBuilder - 它是一个实现细节。我担心如果我向 Conf 添加另一个泛型类型,现在我必须返回并在所有地方添加另一个泛型参数。有什么办法可以避免这种情况吗?

我知道我可以使用闭包代替列表生成器,但我有一个额外的约束,即我的 Conf 结构需要是 Clone,而实际的生成器实现更复杂,并且在构建器中有多个函数和一些状态,这使得闭包方法变得笨拙。

最佳答案

虽然泛型类型似乎可以“感染”您的其余代码,但这正是它们有益的原因!编译器关于使用的大小和具体类型的知识使其能够做出更好的优化决策。

话虽如此,这可能很烦人!如果您有少量实现特征的类型,您还可以构建这些类型的枚举并委托(delegate)给子实现:

enum MyBuilders {
    User(FromUser),
    File(FromFile),
}

impl ListBuilder for MyBuilders {
    fn build(&self, list: &mut Vec<String>) {
        use MyBuilders::*;
        match self {
            User(u) => u.build(list),
            File(f) => f.build(list),
        }
    }
}

// Support code

trait ListBuilder {
    fn build(&self, list: &mut Vec<String>);
}

struct FromUser;
impl ListBuilder for FromUser {
    fn build(&self, list: &mut Vec<String>) {}
}

struct FromFile;
impl ListBuilder for FromFile {
    fn build(&self, list: &mut Vec<String>) {}
}

现在具体类型是Conf<MyBuilders> ,您可以使用类型别名来隐藏它。

当我希望能够在测试期间将测试实现注入(inject)到代码中时,我使用它取得了很好的效果,但在生产代码中使用了一组固定的实现。

enum_dispatch crate有助于构建这种模式。

关于generics - 如何避免将具体结构更改为通用结构所产生的链式 react ?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46854553/

相关文章:

java - Archunit 匹配泛型类型的构造函数

generics - 类型推断在具有静态成员约束的泛型类型上失败

rust - 默认情况下,警告功能应该有一个蛇形标识符

java - 如何避免使用来自不同包的生成类的重复代码

rust - 是否可以在 Rust for 循环中声明变量的类型?

generics - 为什么 Rust 不允许强制转换容器内的特征对象?

rust - 为什么在取消引用的特征对象或切片上调用方法会编译?

python - 如何在traitsui生成的窗口中分配HSplit

c++ - 功能访问限制

Java 通用构建器