0Pricing
Learn Rust Coding · Aula

O padrão Builder

Construa objetos passo a passo.

O padrão Builder é uma aula grátis de Learn Rust Coding no CoddyKit. Esta é a aula 1 de 4. Você pode ler a aula completa abaixo gratuitamente — depois pratica ao vivo no navegador com um editor de código integrado e um tutor de IA 24/7. Faz parte do caminho de aprendizado de Learn Rust Coding, e seu progresso é sincronizado entre a web e o app CoddyKit. O curso de Learn Rust Coding inclui 4 aulas no total.

Por que usar um builder?

Rust não tem argumentos nomeados ou opcionais para funções. Quando uma estrutura tem muitos campos, especialmente opcionais, um construtor com oito parâmetros posicionais se torna ilegível e propenso a erros.

O padrão builder resolve esse problema. Você configura um objeto passo a passo com métodos nomeados e, depois, chama um build() final para produzir o valor. O código fica parecido com uma frase fluida.

A estrutura-alvo

Comece pelo tipo que você realmente quer construir. Aqui, uma configuração de servidor contém um host obrigatório e várias opções ajustáveis opcionais.

Observe que os campos são privados para incentivar a construção por meio do builder, em vez de literais de estrutura.

pub struct ServerConfig {
    host: String,
    port: u16,
    max_connections: usize,
    use_tls: bool,
}

Um tipo de builder separado

A abordagem clássica usa uma segunda estrutura, o builder. Ela espelha o alvo, mas armazena o estado em construção. Os campos opcionais geralmente se tornam Option<T>, para que seja possível distinguir entre “não definido” e “definido explicitamente”.

pub struct ServerConfigBuilder {
    host: String,
    port: Option<u16>,
    max_connections: Option<usize>,
    use_tls: bool,
}

Iniciando o builder

Dê ao builder um construtor que receba apenas os campos obrigatórios. Tudo que for opcional começa como None ou com um valor padrão.

Uma convenção comum é ter um método builder() no tipo-alvo que retorne o builder.

impl ServerConfig {
    pub fn builder(host: impl Into<String>) -> ServerConfigBuilder {
        ServerConfigBuilder {
            host: host.into(),
            port: None,
            max_connections: None,
            use_tls: false,
        }
    }
}

Métodos de configuração recebem self por valor

Cada método de configuração consome self, altera um campo e retorna self. Retornar o valor pertencente ao objeto permite encadear chamadas de forma fluida.

Esse encadeamento baseado em propriedade é o estilo idiomático de Rust e evita complicações com tempos de vida.

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
    }
}

Aplicando valores padrão em build()

O build() final transforma o builder no tipo real. É nesse ponto que você preenche os valores padrão de tudo que ainda for None, usando 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,
        }
    }
}

Construção fluida

Agora a construção pode ser lida de cima para baixo. Os dados obrigatórios entram em builder(); cada ajuste opcional é uma chamada com nome claro.

Os campos que você ignorar recebem silenciosamente seus valores padrão.

fn main() {
    let cfg = ServerConfig::builder("localhost")
        .port(9000)
        .use_tls(true)
        .build();
    println!("{}:{} tls={}", cfg.host, cfg.port, cfg.use_tls);
}

Um exemplo completo executável

Aqui está o padrão completo, condensado em um único programa que você pode executar. Ele mostra que os campos ignorados usam valores padrão dentro de 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);
}

build passível de falha com Result

Às vezes, uma configuração pode ser inválida, por exemplo, quando a porta é zero. Faça build() retornar Result, para que as falhas de validação apareçam como erros recuperáveis, em vez de pânicos.

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 })
    }
}

A crate derive_builder

Escrever builders manualmente é repetitivo. A crate derive_builder gera o builder completo a partir de uma anotação.

Você anota os campos com valores padrão e obtém um FooBuilder gerado, com métodos de configuração e um build() passível de falha, sem trabalho adicional.

use derive_builder::Builder;

#[derive(Builder)]
struct Channel {
    #[builder(default = "8080")]
    port: u16,
    name: String,
}

Builders com propriedade versus referência mutável

Existem dois estilos. O estilo com propriedade consome self e permite encadeamentos naturais. O estilo &mut self retorna &mut Self e permite dividir a construção entre várias instruções sem precisar reatribuir a variável.

O estilo com propriedade é mais comum para construções únicas; o estilo mutável é adequado para configurações condicionais em laços.

impl ServerConfigBuilder {
    pub fn port_ref(&mut self, port: u16) -> &mut Self {
        self.port = Some(port);
        self
    }
}

Verificação rápida

Teste seu entendimento sobre o estilo de builder com self pertencente ao objeto.

Recapitulação

O padrão builder contorna a ausência de argumentos opcionais em Rust. Um tipo builder mantém o estado em construção, os métodos de configuração consomem e retornam self para permitir encadeamentos, e build() aplica valores padrão para produzir o valor final.

Use Result em build() para validação e recorra a derive_builder para evitar o código repetitivo.

Perguntas Frequentes

A aula “O padrão Builder” é grátis?

Sim — o texto completo de “O padrão Builder” é grátis para ler aqui na web. Para praticá-la interativamente (um editor de código integrado e um tutor de IA 24/7) e desbloquear o restante do curso de Learn Rust Coding, atualize para CoddyKit PRO. O curso de Learn Rust Coding inclui 4 aulas no total.

O que vou aprender em “O padrão Builder”?

Construa objetos passo a passo. Você pratica Learn Rust Coding com código prático que executa diretamente no navegador, e um tutor de IA 24/7 responde suas dúvidas enquanto trabalha na aula.

Preciso ter experiência prévia para começar Learn Rust Coding?

Nenhuma experiência prévia é necessária. Learn Rust Coding no CoddyKit é estruturado para alunos iniciantes até avançados, então você pode começar aqui ou desde o início e aprender no seu ritmo. Esta é a aula 1 de 4.

Quanto tempo leva a aula “O padrão Builder”?

A maioria das aulas CoddyKit leva cerca de 5–10 minutos. Cada uma é compacta e interativa, então você faz progresso constante e retoma exatamente de onde parou entre web e app.

Posso escrever e executar código nesta aula de Learn Rust Coding?

Sim. Cada aula de Learn Rust Coding inclui um editor de código integrado, então você escreve e executa código real direto no navegador e recebe feedback de IA instantaneamente — nenhuma configuração local necessária.

Todas as aulas deste curso

  1. O padrão Builder
  2. O padrão Newtype
  3. Builders com estado de tipo
  4. Ergonomia de Deref e wrappers
← Voltar para Learn Rust Coding