Padrões de Projeto em Rust: Técnicas Avançadas com Exemplos de Código

Treinador Online de Python para Iniciantes

Aprenda Python facilmente sem sobrecarga teórica. Resolva tarefas práticas com verificação automática e escreva código diretamente no navegador.

Start Course
```html

Padrões de Projeto em Rust com Exemplos: Nível Avançado



Rust é uma linguagem que muda a abordagem de design. Os padrões clássicos do GoF frequentemente exigem adaptação devido ao sistema estrito de ownership, lifetime e à ausência de herança. Neste artigo, vamos analisar padrões de projeto avançados que não apenas funcionam em Rust, mas utilizam seus pontos fortes: segurança de memória, abstrações de custo zero e um poderoso sistema de tipos.



1. Padrão Builder com Verificações em Tempo de Compilação



O Builder clássico em Rust geralmente é implementado através de uma struct com campos opcionais. Em um nível avançado, podemos usar o sistema de tipos para verificar campos obrigatórios em tempo de compilação. Isso elimina erros de runtime do tipo "esqueci de definir um campo obrigatório".



A implementação via Type State (estado do tipo) permite tornar o Builder seguro e autodocumentado.



// Estados para o Builderstruct Empty;struct WithName(String);struct WithAge(u8);struct Ready(WithName, WithAge);

struct PersonBuilder<State> { state: State,}

impl PersonBuilder<Empty> { pub fn new() -> Self { PersonBuilder { state: Empty } } pub fn name(self, name: &str) -> PersonBuilder<WithName> { PersonBuilder { state: WithName(name.to_string()), } }}

impl PersonBuilder<WithName> { pub fn age(self, age: u8) -> PersonBuilder<Ready> { PersonBuilder { state: Ready(self.state, WithAge(age)), } }}

impl PersonBuilder<Ready> { pub fn build(self) -> Person { Person { name: self.state.0 .0, age: self.state.1 .0, } }}

struct Person { name: String, age: u8,}

fn main() { // Compila - todos os campos foram definidos let person = PersonBuilder::new() .name("Alice") .age(30) .build(); // Não compila: falta name() // let person = PersonBuilder::new().age(30).build(); println!("{} tem {} anos", person.name, person.age);}


Vantagem: erros de configuração são detectados em tempo de compilação, e não durante a execução. Isso é especialmente valioso para objetos complexos com dezenas de parâmetros.



2. Padrão RAII e Smart Pointers para Gerenciamento de Recursos



RAII (Resource Acquisition Is Initialization) não é apenas um padrão, mas uma filosofia do Rust. Cada recurso (memória, arquivo, socket, lock) deve ser adquirido no construtor e liberado no destrutor. Rust implementa isso através das traits Drop e do sistema de ownership.



Exemplo avançado: criação de um wrapper RAII para um mutex com liberação automática.



use std::ops::Deref;use std::sync::{Arc, Mutex};

struct Guard<T> { data: T,}

impl<T> Drop for Guard<T> { fn drop(&mut self) { println!("Recurso liberado!"); }}

impl<T> Deref for Guard<T> { type Target = T; fn deref(&self) -> &Self::Target { &self.data }}

struct ResourceManager<T> { resource: Arc<Mutex<T>>,}

impl<T> ResourceManager<T> { fn new(data: T) -> Self { ResourceManager { resource: Arc::new(Mutex::new(data)), } } fn acquire(&self) -> Guard<std::sync::MutexGuard<T>> { let guard = self.resource.lock().unwrap(); Guard { data: guard } }}

fn main() { let manager = ResourceManager::new(42); { let guard = manager.acquire(); println!("Valor: {}", *guard); // guard sai de escopo -> libera o mutex automaticamente } // Imprime "Recurso liberado!" println!("Mutex está disponível novamente");}


Ideia chave: o destructor é cha ```

Blogs

Book Recommendations