Hello all,
I'm trying to implement a "builder" for a struct, and am running into a wall because the struct in question uses a Box<dyn trait>
type for a field. I've created a (non-functional) playground to illustrate. I'll share an excerpt here:
struct Gizmo {
buzzer: Box<dyn Buzz>
}
struct GizmoBuilder {
buzzer: Box<dyn Buzz>
}
impl GizmoBuilder {
pub fn new() -> Self {
GizmoBuilder {
buzzer: Box::new(Widget::new())
}
}
pub fn build(&self) -> Gizmo {
Gizmo {
buzzer: self.buzzer
}
}
}
Of course, I cannot move out of self.buzzer which is behind a shared reference
. Are there any recommendations for a way that I could achieve this without modifying the underlying Gizmo
struct?
Usually the build
method consumes the builder by having a self
param, rather than &self
. Have you tried that? You should be able to move out of self
.
2 Likes
Conventionally, builder types are consumed when they build the final output. This avoids the whole issue:
impl GizmoBuilder {
pub fn new() -> Self {
GizmoBuilder {
buzzer: Box::new(Widget::new())
}
}
pub fn build(self) -> Gizmo {
Gizmo {
buzzer: self.buzzer
}
}
}
However, the builder is then not reusable. Often, making them Clone
is a reasonable way to support reuse, but with your design that's a bit awkward.
Alternately, you can postpone creation of the Widget
until it's needed:
struct GizmoBuilder;
impl GizmoBuilder {
pub fn new() -> Self {
GizmoBuilder
}
pub fn build(&self) -> Gizmo {
Gizmo {
buzzer: self.make_buzzer(),
}
}
fn make_buzzer(&self) -> Box<dyn Buzz> {
Box::new(Widget::new())
}
}
1 Like
But here's one way how anyhow. Practically speaking, implementors of Buzz
have to be Clone
with this approach. (Longer explanation.)
Very delayed response, but just wanted to say thank you everyone here! The solution that I used was to consume self
in the build
function as @derspiny and @jumpnbrownweasel suggested. I marked @derspiny's response as the solution only because he included a code snippet. Thanks again!
3 Likes