How do you properly use a builder pattern that expects method chaining in a loop? Using an example from log4rs. Notice self
isn't a reference in 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
}
}
Doing this below results in an error because (I think) cb
is getting moved to the memory being returned by .appender()
.
let cb = ConfigBuilder::new();
for x in ys {
cb.appender(x);
}
This below appears to work. Is this the only way to do it?
let mut cb = ConfigBuilder::new();
for x in ys {
cb = cb.appender(x);
}
Is this the only way to do it?
Semantically it is the critical way, though there are other ways to write it. The appender
function takes mut self
so it will take ownership of the cb
variable's value and make the variable unusable after that point. It could have been designed to borrow a reference, but chaining is nice. Since you're in a loop, the builder needs to be available on the next iteration, so you need to assign the value to something new. This means that
let mut cb = ConfigBuilder::new();
for x in ys {
cb = cb.appender(x);
}
is indeed one way to do that. Another way would be to use Iterator
's .fold
to do
let cb = ys.into_iter()
.fold(ConfigBuilder::new(), |cb, x| cb.appender(x));
which keeps everything in one assignment, but is otherwise pretty much the same.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With