Injeção de Dependência (Dependency Injection) em Rust para Iniciantes

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

Introdução: Por que Dependency Injection é importante em Rust?

\n\n

Ao escrever programas em Rust, mais cedo ou mais tarde você enfrentará uma situação em que um módulo (por exemplo, um serviço ou controlador) precisa usar as capacidades de outro módulo (banco de dados, API, logger). A maneira mais simples é criar o objeto necessário diretamente dentro do código que o utiliza:

\n\n
struct UserService;\n\nimpl UserService {\n    fn get_user(&self, id: u32) -> String {\n        let db = Database::new(); // ❌ Acoplamento rígido\n        db.query_user(id)\n    }\n}\n
\n\n

Essa abordagem cria um acoplamento rígido (tight coupling). O código se torna difícil de testar, reutilizar e modificar. Dependency Injection (DI) é um padrão onde as dependências são passadas para o objeto de fora, em vez de serem criadas dentro dele. Rust, sendo uma linguagem com sistema de propriedade e traits, oferece maneiras elegantes de implementar DI sem frameworks.

\n\n

Neste artigo, vamos explorar como injetar dependências em Rust com exemplos práticos: desde a simples passagem de structs até o uso de traits e ponteiros inteligentes.

\n\n

1. Abordagem básica: Passando dependências através do construtor

\n\n

A maneira mais simples de injetar uma dependência em Rust é passá-la como argumento do construtor ou função. Vamos considerar um exemplo com um logger.

\n\n

Exemplo ruim (sem DI)

\n\n
struct ConsoleLogger;\n\nimpl ConsoleLogger {\n    fn log(&self, msg: &str) {\n        println!("[LOG]: {}", msg);\n    }\n}\n\nstruct OrderService {\n    logger: ConsoleLogger, // ❌ Acoplamento rígido a um tipo específico\n}\n\nimpl OrderService {\n    fn new() -> Self {\n        Self {\n            logger: ConsoleLogger, // Criado internamente\n        }\n    }\n\n    fn place_order(&self, item: &str) {\n        self.logger.log(&format!("Pedido: {}", item));\n    }\n}\n
\n\n

Exemplo bom (com DI)

\n\n
struct ConsoleLogger;\n\nimpl ConsoleLogger {\n    fn log(&self, msg: &str) {\n        println!("[LOG]: {}", msg);\n    }\n}\n\nstruct OrderService {\n    logger: ConsoleLogger, // Dependência passada de fora\n}\n\nimpl OrderService {\n    // Construtor recebe a dependência\n    fn new(logger: ConsoleLogger) -> Self {\n        Self { logger }\n    }\n\n    fn place_order(&self, item: &str) {\n        self.logger.log(&format!("Pedido: {}", item));\n    }\n}\n\nfn main() {\n    let logger = ConsoleLogger;\n    let service = OrderService::new(logger);\n    service.place_order("Livro sobre Rust");\n}\n
\n\n

O que mudou? Agora OrderService não cria o logger por conta própria. Ele o recebe pronto. Isso já é DI, mas há uma nuance: ainda estamos presos ao tipo específico ConsoleLogger. Para tornar o código flexível, precisamos usar traits.

\n\n

2. Usando traits para abstrair dependências

\n\n

Traits em Rust são análogos às interfaces em outras linguagens. Eles permitem definir um contrato que as dependências devem seguir.

\n\n

Definindo o trait Logger

\n\n
trait Logger {\n    fn log(&self, msg: &str);\n}\n\nstruct ConsoleLogger;\nimpl Logger for ConsoleLogger {\n    fn log(&self, msg: &str) {\n        println!("[Console]: {}", msg);\n    }\n}\n\nstruct FileLogger {\n    filename: String,\n}\nimpl Logger for FileLogger {\n    fn log(&self, msg: &str) {\n        // Simulação de escrita em arquivo\n        println!("[Arquivo {}]: {}", self.filename, msg);\n    }\n}\n
\n\n

Injetando o trait através de genéricos (generics)

\n\n
struct OrderService<L: Logger> {\n    logger: L, // Tipo genérico que implementa o trait Logger\n}\n\nimpl<L: Logger> OrderService<L> {\n    fn new(logger: L) -> Self {\n        Self { logger }\n    }\n\n    fn place_order(&self, item: &str) {\n        self.logger.log(&format!("Pedido: {}", item));\n    }\n}\n\nfn main() {\n    let console_logge                

Blogs

Book Recommendations