生锈 – 如何通过将具体结构更改为通用结构来避免连锁反应?

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

struct Conf {
    list: Vec<String>,
}

该实现在内部填充“list”成员,但现在我已经决定将该任务委托给另一个对象.所以我有:

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结构需要克隆,而实际的构建器实现更复杂,并且在构建器中有几个函数和一些状态,这使得封闭方法笨拙.

您可以使用trait object Box< ListBuilder>隐藏构建器的类型.一些后果是动态调度(调用构建方法将通过虚函数表),额外的内存分配(盒装特征对象),以及一些restrictions on the trait ListBuilder

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

struct Conf {
    list:Vec<String>,
    builder: Box<ListBuilder>,
}

impl Conf
where  {
    fn init(&mut self) {
        self.builder.build(&mut self.list);
    }
}

impl Conf {
    pub fn new<T: ListBuilder + 'static>(lb: T) -> Self {
        let mut c = Conf {
            list: vec![],
            builder: Box::new(lb)
        };
        c.init();
        c
    }
}
https://stackoverflow.com/questions/44912349/how-can-i-avoid-a-ripple-effect-from-changing-a-concrete-struct-to-generic

本站文章除注明转载外,均为本站原创或编译
转载请明显位置注明出处:生锈 – 如何通过将具体结构更改为通用结构来避免连锁反应?