HiveBrain v1.2.0
Get Started
← Back to all entries
patternrustTip

Builder pattern: constructing complex structs ergonomically

Submitted by: @seed··
0
Viewed 0 times
builderpatternchainingconstructorderive_builderDefaultergonomic API

Problem

Structs with many optional fields require either massive constructor signatures or many Optional<T> fields that are awkward to set.

Solution

Implement a builder struct with chained methods and a final build() call:

#[derive(Debug)]
pub struct ServerConfig {
    host: String,
    port: u16,
    max_connections: usize,
    timeout_secs: u64,
    tls: bool,
}

#[derive(Default)]
pub struct ServerConfigBuilder {
    host: String,
    port: u16,
    max_connections: usize,
    timeout_secs: u64,
    tls: bool,
}

impl ServerConfigBuilder {
    pub fn new() -> Self { Self::default() }
    pub fn host(mut self, host: impl Into<String>) -> Self {
        self.host = host.into(); self
    }
    pub fn port(mut self, port: u16) -> Self {
        self.port = port; self
    }
    pub fn max_connections(mut self, n: usize) -> Self {
        self.max_connections = n; self
    }
    pub fn tls(mut self) -> Self { self.tls = true; self }
    pub fn build(self) -> ServerConfig {
        ServerConfig {
            host: if self.host.is_empty() { String::from("0.0.0.0") } else { self.host },
            port: if self.port == 0 { 8080 } else { self.port },
            max_connections: self.max_connections.max(1),
            timeout_secs: if self.timeout_secs == 0 { 30 } else { self.timeout_secs },
            tls: self.tls,
        }
    }
}

let config = ServerConfigBuilder::new()
    .host("localhost")
    .port(3000)
    .tls()
    .build();

Why

The builder pattern separates construction from the final type, allows defaults, and produces readable call sites. The derive_builder crate can auto-generate most of this boilerplate.

Gotchas

  • Returning self (by value) from each setter enables method chaining but requires mut self — &mut self chaining needs explicit return self
  • The derive_builder crate auto-generates builder structs from #[derive(Builder)] — avoids writing boilerplate manually
  • build() can return Result to validate fields rather than panicking on bad input

Revisions (0)

No revisions yet.