liveBook · Manning

Builder pattern

As explained in Idiomatic Rust

The builder pattern is a construction pattern that assembles a complex value through a sequence of configurable operations before producing the final value.

The builder pattern assembles a complex value through configurable operations before producing the final value. In Rust, it avoids exposing structures directly and compensates for the absence of optional arguments, while improving encapsulation, convenience, separation of concerns, ergonomics, and safety. section 5.3

A basic Rust builder typically:

  • Stores the value under construction inside a separate builder type. section 5.3.1
  • Provides configurable methods such as with_make, with_model, with_size, and with_color. section 5.3.1
  • Initializes with new, applies settings, and finishes with build. section 5.3.1
  • Can consume itself on each setting method and return a new builder, enabling fluent chaining. section 5.4.1

Building a bicycle

let mut builder = BicycleBuilder::new(); builder.with_make("Huffy"); builder.with_model("Radio"); builder.with_size(46); builder.with_color("red"); let bicycle = builder.build(); A fluent variant instead consumes each builder and returns Self, allowing configuration methods to be chained. Its implementation uses owned struct-update syntax, so the previous builder is moved. section 5.3.1 section 5.4.1

Listing 5.4 Code for builder pattern
#[derive(Debug)]
struct Bicycle {
    make: String,
    model: String,
    size: i32,
    color: String,
}

impl Bicycle {                  #1
    fn make(&self) -> &String {
        &self.make
    }
    fn model(&self) -> &String {
        &self.model
    }
    fn size(&self) -> i32 {
        self.size
    }
    fn color(&self) -> &String {
        &self.color
    }
}

struct BicycleBuilder {
    bicycle: Bicycle,        #2
}

impl BicycleBuilder {
    fn new() -> Self {         #3
        Self {
            bicycle: Bicycle {
                make: String::new(),
                model: String::new(),
                size: 0,
                color: String::new(),
            },
        }
    }
    fn with_make(&mut self, make: &str) {    #4
        self.bicycle.make = make.into()
    }
    fn with_model(&mut self, model: &str) {
        self.bicycle.model = model.into()
    }
    fn with_size(&mut self, size: i32) {
        self.bicycle.size = size
    }
    fn with_color(&mut self, color: &str) {
        self.bicycle.color = color.into()
    }
    fn build(self) -> Bicycle {       #5
        self.bicycle
    }
}

Inspect the complete Rust implementation, including the Bicycle value, encapsulated builder state, initialization, setters, and build operation. section 5.3.1

How Idiomatic Rust covers it

How deep it goes
Implements mutable and fluent builders, explaining ownership and struct-update moves while noting added complexity.
Examples
Demonstrates a BicycleBuilder that configures make, model, size, and color before producing a Bicycle.
What it assumes
Assumes Rust generics, traits, pattern matching, functional features, ownership, and basic macro familiarity.
What you can do after
Build configurable Rust values with mutable setters or consuming fluent methods, then recognize when added builder complexity is justified.
How it connects
Connects builders with encapsulation, separation of concerns, currying, fluent interfaces, macros, ownership, and struct update syntax.

Also explained in

Compare how 6 books explain builder pattern →

Related concepts

This explainer was generated by Manning's knowledge graph from the text of Idiomatic Rust. The section links point to the parts of the book it draws on.