Padrões de Projeto em Rust 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
Here is the translated HTML content in Portuguese (Português), with all HTML tags preserved and only the text content translated. ```html

Padrões de Projeto em Rust: Guia Prático com Exemplos



Padrões de projeto são soluções comprovadas para problemas típicos de desenvolvimento. Em Rust, devido ao seu sistema único de ownership e modelo de memória, a implementação de padrões clássicos muitas vezes difere de linguagens com garbage collection. Neste artigo, vamos abordar três padrões principais: Singleton, Builder e Strategy, adaptados às particularidades do Rust.



1. Padrão Singleton em Rust: Estado global sem unsafe



O Singleton garante que uma classe tenha apenas uma instância e fornece um ponto de acesso global a ela. Em Rust, a crate once_cell ou o estável std::sync::OnceLock (a partir do Rust 1.70) são ideais para isso.



Implementação com OnceLock

use std::sync::OnceLock;

pub struct Logger { level: String,}

impl Logger { pub fn global() -> &'static Logger { static INSTANCE: OnceLock<Logger> = OnceLock::new(); INSTANCE.get_or_init(|| Logger { level: "info".to_string(), }) }

pub fn log(&self, msg: &str) { println!("[{}] {}", self.level, msg); }}

fn main() { let logger = Logger::global(); logger.log("Olá, Rust!"); // Logger::global() retornará a mesma instância}


Vantagens: Segurança (sem unsafe), inicialização lazy, thread safety. Desvantagem — estado global dificulta os testes.



2. Padrão Builder: Construção de objetos complexos



O Builder separa a construção de um objeto complexo de sua representação. Em Rust, ele é especialmente útil para structs com muitos campos opcionais.



Exemplo: Configuração de um cliente HTTP

pub struct HttpClient {    url: String,    timeout: u64,    headers: Vec<(String, String)>,}

pub struct HttpClientBuilder { url: String, timeout: Option<u64>, headers: Vec<(String, String)>,}

impl HttpClientBuilder { pub fn new(url: &str) -> Self { HttpClientBuilder { url: url.to_string(), timeout: None, headers: vec![], } }

pub fn timeout(mut self, secs: u64) -> Self { self.timeout = Some(secs); self }

pub fn header(mut self, key: &str, value: &str) -> Self { self.headers.push((key.to_string(), value.to_string())); self }

pub fn build(self) -> HttpClient { HttpClient { url: self.url, timeout: self.timeout.unwrap_or(30), headers: self.headers, } }}

fn main() { let client = HttpClientBuilder::new("https://api.example.com") .timeout(10) .header("Authorization", "Bearer token123") .build(); println!("URL do cliente: {}", client.url);}


Importante: O uso de self (não &self) nos métodos do builder evita clonagem e torna a API mais ergonômica.



3. Padrão Strategy: Algoritmos como estratégias intercambiáveis



O Strategy define uma família de algoritmos, encapsula cada um deles e os torna intercambiáveis. Em Rust, isso é implementado através de traits e dispatch dinâmico (Box<dyn Trait>).



Exemplo: Sistema de ordenação

trait SortStrategy {    fn sort(&self, data: &mut [i32]);}

struct BubbleSort;impl SortStrategy for BubbleSort { fn sort(&self, data: &mut [i32]) { let n = data.len(); for i in 0..n { for j in 0..n - i - 1 { if data[j] > data[j + 1] { data.swap(j, j + 1); } } } }}

struct QuickSort;impl SortStrategy for QuickSort { fn sort(&self, da ```

Blogs

Book Recommendations