Le patron Builder
Construisez des objets étape par étape.
Le patron Builder est une leçon Learn Rust Coding gratuite sur CoddyKit. Ceci est la leçon 1 sur 4. Tu peux lire la leçon complète ci-dessous gratuitement — puis la pratiquer en direct dans le navigateur avec un éditeur de code intégré et un tuteur IA 24/7. Elle fait partie du parcours d'apprentissage Learn Rust Coding, et ta progression se synchronise sur le web et l'application CoddyKit. Le cours Learn Rust Coding comprend 4 leçons au total.
Certaines parties de cette leçon n'ont pas encore été traduites et s'affichent en anglais.
Why a Builder?
Rust has no named or optional function arguments. When a struct has many fields, especially optional ones, a constructor with eight positional parameters becomes unreadable and error-prone.
The builder pattern solves this. You configure an object step by step with named methods, then call a final build() to produce the value. It reads like a fluent sentence.
The Target Struct
Start with the type you actually want to construct. Here a server configuration carries a required host plus several optional knobs.
Notice the fields are private to encourage construction through the builder rather than struct literals.
pub struct ServerConfig {
host: String,
port: u16,
max_connections: usize,
use_tls: bool,
}A Separate Builder Type
The classic approach uses a second struct, the builder. It mirrors the target but stores work-in-progress state. Optional fields often become Option<T> so you can tell "unset" from "explicitly set".
pub struct ServerConfigBuilder {
host: String,
port: Option<u16>,
max_connections: Option<usize>,
use_tls: bool,
}Starting the Builder
Give the builder a constructor that takes only the required fields. Everything optional starts as None or a default.
A common convention is a builder() method on the target type that returns the builder.
impl ServerConfig {
pub fn builder(host: impl Into<String>) -> ServerConfigBuilder {
ServerConfigBuilder {
host: host.into(),
port: None,
max_connections: None,
use_tls: false,
}
}
}Setter Methods Take self by Value
Each setter consumes self, mutates a field, and returns self. Returning the owned value lets you chain calls fluently.
This ownership-based chaining is the idiomatic Rust style and avoids lifetime headaches.
impl ServerConfigBuilder {
pub fn port(mut self, port: u16) -> Self {
self.port = Some(port);
self
}
pub fn use_tls(mut self, yes: bool) -> Self {
self.use_tls = yes;
self
}
}Applying Defaults in build()
The terminal build() turns the builder into the real type. This is where you fill in defaults for anything still None using unwrap_or.
impl ServerConfigBuilder {
pub fn build(self) -> ServerConfig {
ServerConfig {
host: self.host,
port: self.port.unwrap_or(8080),
max_connections: self.max_connections.unwrap_or(128),
use_tls: self.use_tls,
}
}
}Fluent Construction
Now construction reads top to bottom. Required data goes into builder(); each optional tweak is a clearly named call.
Fields you skip silently take their defaults.
fn main() {
let cfg = ServerConfig::builder("localhost")
.port(9000)
.use_tls(true)
.build();
println!("{}:{} tls={}", cfg.host, cfg.port, cfg.use_tls);
}A Complete Runnable Example
Here is the whole pattern condensed into one program you can run. It shows that skipped fields fall back to defaults inside build().
struct Config { name: String, retries: u32 }
struct Builder { name: String, retries: Option<u32> }
impl Config {
fn builder(name: &str) -> Builder {
Builder { name: name.to_string(), retries: None }
}
}
impl Builder {
fn retries(mut self, n: u32) -> Self { self.retries = Some(n); self }
fn build(self) -> Config {
Config { name: self.name, retries: self.retries.unwrap_or(3) }
}
}
fn main() {
let c = Config::builder("job").build();
println!("{} retries={}", c.name, c.retries);
}Fallible build with Result
Sometimes a configuration can be invalid, for example a port of zero. Make build() return Result so validation failures surface as recoverable errors instead of panics.
impl ServerConfigBuilder {
pub fn try_build(self) -> Result<ServerConfig, String> {
let port = self.port.unwrap_or(8080);
if port == 0 {
return Err("port must be non-zero".into());
}
Ok(ServerConfig { host: self.host, port,
max_connections: self.max_connections.unwrap_or(128),
use_tls: self.use_tls })
}
}The derive_builder Crate
Writing builders by hand is repetitive. The derive_builder crate generates the whole builder from an annotation.
You annotate fields with defaults and get a generated FooBuilder with setters and a fallible build() for free.
use derive_builder::Builder;
#[derive(Builder)]
struct Channel {
#[builder(default = "8080")]
port: u16,
name: String,
}Owned vs Mutable-Reference Builders
Two styles exist. The owned style consumes self and chains naturally. The &mut self style returns &mut Self and lets you split building across statements without re-binding.
Owned is more common for one-shot construction; the mutable style suits conditional configuration in loops.
impl ServerConfigBuilder {
pub fn port_ref(&mut self, port: u16) -> &mut Self {
self.port = Some(port);
self
}
}Quick Check
Test your understanding of the owned-self builder style.
Recap
The builder pattern works around Rust's lack of optional arguments. A builder type holds work-in-progress state, setters consume and return self for chaining, and build() applies defaults to produce the final value.
Use Result from build() for validation, and reach for derive_builder to skip the boilerplate.
Questions Fréquemment Posées
La leçon « Le patron Builder » est-elle gratuite ?
Oui — le texte complet de « Le patron Builder » est gratuit à lire ici sur le web. Pour la pratiquer de manière interactive (un éditeur de code intégré et un tuteur IA 24/7) et déverrouiller le reste du cours Learn Rust Coding, passe à CoddyKit PRO. Le cours Learn Rust Coding comprend 4 leçons au total.
Qu'est-ce que j'apprendrai dans « Le patron Builder » ?
Construisez des objets étape par étape. Tu pratiques Learn Rust Coding avec du code pratique que tu exécutes directement dans le navigateur, et un tuteur IA 24/7 répond à tes questions au fur et à mesure que tu avances dans la leçon.
Dois-je avoir de l'expérience pour commencer Learn Rust Coding ?
Aucune expérience préalable n'est requise. Learn Rust Coding sur CoddyKit est structuré pour les débutants jusqu'aux apprenants avancés, donc tu peux commencer ici ou depuis le début et avancer à ton rythme. Ceci est la leçon 1 sur 4.
Combien de temps prend la leçon « Le patron Builder » ?
La plupart des leçons CoddyKit prennent environ 5–10 minutes. Chacune est courte et interactive, tu progresses régulièrement et tu repiques exactement où tu t'es arrêté sur le web et l'app.
Peux-tu écrire et exécuter du code dans cette leçon Learn Rust Coding ?
Oui. Chaque leçon Learn Rust Coding inclut un éditeur de code intégré, tu écris et exécutes du vrai code directement dans ton navigateur et tu reçois des retours IA instantanés — aucune configuration locale requise.
Toutes les leçons de ce cours
- Le patron Builder
- Le patron Newtype
- Builders fondés sur l’état du type
- Ergonomie de Deref et des enveloppes