2017-08-05 39 views
1

如何正确使用预计在循环中使用method chaining的构建器模式?使用来自log4rs的示例。注意self不是appender中的参考。如何在循环中使用链式生成器模式而不会产生编译器错误?

//builder pattern from log4rs 

pub struct ConfigBuilder { 
    appenders: Vec<Appender>, 
    loggers: Vec<Logger>, 
} 

impl ConfigBuilder { 
    pub fn appender(mut self, appender: Appender) -> ConfigBuilder { 
     self.appenders.push(appender); 
     self 
    } 
} 

做一个错误下面这样的结果,因为(我认为)cb是越来越移动到.appender()返回的内存。

let cb = ConfigBuilder::new(); 
for x in ys { 
    cb.appender(x); 
} 

下面这似乎工作。这是唯一的方法吗?

let mut cb = ConfigBuilder::new(); 
for x in ys { 
    cb = cb.appender(x); 
} 
+0

你已经让'appender'获得了所有权并返回新的构建器,所以你需要将返回值放在某个地方。你故意选择这种设计吗?如果你想让第一个例子的循环工作,你需要传递一个可变的自引用。 – loganfsmyth

+0

@loganfsmyth - 对不起,如果我不清楚,那个例子来自log4rs包。 https://crates.io/crates/log4rs。不是我的设计。 – marathon

+0

另请参阅https://stackoverflow.com/q/34362094/155423 – Shepmaster

回答

4

这是做到这一点的唯一途径?

从语义上讲,它是关键的方法,尽管还有其他写法。 appender功能需要mut self,因此它将取得cb变量值的所有权,并使该变量在该点之后不可用。它本可以设计借用一个参考,但链接很好。由于您处于循环中,因此构建器需要在下一次迭代中可用,因此您需要将值分配给新的东西。这意味着,

let mut cb = ConfigBuilder::new(); 
for x in ys { 
    cb = cb.appender(x); 
} 

的确是一种方法来做到这一点。另一种方法是使用Iterator's .fold

let cb = ys.into_iter() 
    .fold(ConfigBuilder::new(), |cb, x| cb.appender(x)); 

其保持在一个分配的一切,但在其他方面几乎相同。