0Pricing
Learn Rust Coding · Leçon

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

  1. Le patron Builder
  2. Le patron Newtype
  3. Builders fondés sur l’état du type
  4. Ergonomie de Deref et des enveloppes
← Retour à Learn Rust Coding