Builder pattern for complex struct initialization
Marcus Chen
Jan 2026
1 tab
pub struct Server {
host: String,
port: u16,
workers: usize,
}
pub struct ServerBuilder {
host: Option<String>,
port: Option<u16>,
workers: usize,
}
impl ServerBuilder {
pub fn new() -> Self {
Self { host: None, port: None, workers: 4 }
}
pub fn host(mut self, host: String) -> Self {
self.host = Some(host);
self
}
pub fn port(mut self, port: u16) -> Self {
self.port = Some(port);
self
}
pub fn build(self) -> Result<Server, &'static str> {
Ok(Server {
host: self.host.ok_or("host is required")?,
port: self.port.ok_or("port is required")?,
workers: self.workers,
})
}
}
1 file · rust
Explain with highlit
For structs with many optional fields, the builder pattern provides a fluent API for construction. I define a separate Builder struct with methods that return self for chaining. The final build() method validates and returns the target struct. This is more ergonomic than constructors with many arguments, and it allows validation logic (required fields, invariants). The derive_builder crate can auto-generate builders, but for complex cases I write them manually. I use builders for config structs, clients with many options, and anywhere you'd use optional named parameters in other languages. The pattern also makes it easy to add new fields without breaking existing code, improving API stability.