A palavra-chave impl | Rust
- A palavra-chave
impl| Rust
Em Rust, a palavra-chave impl (abreviação de "implement") é usada para associar métodos, funções e implementações de traits a tipos definidos pelo usuário, como structs, enums e union. O uso de impl pode ser dividido em dois contextos principais:
1. Implementação Intrínseca (impl Tipo)
Essa forma é usada para adicionar métodos e funções associadas diretamente a um tipo, sem envolvimento de traits.
Exemplo:
struct Pessoa {
nome: String,
idade: u8,
}
impl Pessoa {
// Método: recebe `self`
fn fazer_aniversario(&mut self) {
self.idade += 1;
}
// Função associada: não recebe `self`, semelhante a um construtor
fn nova(nome: &str) -> Self {
Pessoa {
nome: nome.to_string(),
idade: 0,
}
}
}
Características:
- Métodos podem receber
self,&self, ou&mut self. - Funções associadas são chamadas com
Tipo::funcao(). - Várias
implpodem ser criadas para o mesmo tipo (não precisam estar todas em um único bloco).
2. Implementação de Traits (impl Trait for Tipo)
Neste caso, usamos impl para associar um comportamento (contrato) definido por um trait a um tipo. Isso é o que permite o polimorfismo em Rust.
Exemplo:
trait Imprimivel {
fn imprimir(&self);
}
impl Imprimivel for Pessoa {
fn imprimir(&self) {
println!("{} ({})", self.nome, self.idade);
}
}
Características:
- Um tipo pode implementar múltiplos traits.
- Um trait pode ser implementado para múltiplos tipos.
- É obrigatório implementar todos os métodos do trait (a menos que tenham default).
3. Implementações Genéricas (impl<T> Tipo<T>)
Você pode usar impl com tipos genéricos, permitindo reuso de lógica para múltiplas instâncias de um tipo parametrizado.
Exemplo:
struct Caixa<T> {
valor: T,
}
impl<T> Caixa<T> {
fn novo(valor: T) -> Self {
Caixa { valor }
}
fn pegar(&self) -> &T {
&self.valor
}
}
4. Implementações Condicionais (impl<T> ... where ...)
Permite restringir uma implementação a casos em que o tipo genérico satisfaça certas condições (por exemplo, implemente um trait específico).
Exemplo:
use std::fmt::Display;
impl<T> Caixa<T>
where
T: Display,
{
fn imprimir(&self) {
println!("Valor: {}", self.valor);
}
}
5. Implementação de Traits para Tipos Primitivos (em contexto local)
É possível implementar traits em tipos externos apenas se você for o dono de ao menos um dos dois (coerência do Rust, conhecida como orphan rule).
✅ Válido:
trait MeuTrait {
fn saudacao(&self);
}
impl MeuTrait for String {
fn saudacao(&self) {
println!("Olá, {}!", self);
}
}
❌ Inválido (dois tipos externos):
impl Display for Vec<String> {
// ERRO: Display e Vec<String> são ambos externos ao seu crate.
}
6. Implementação Padrão com default impl (usada em traits "auto")
Embora não muito comum, você pode fornecer uma implementação padrão via traits usando default fn, e sobrescrevê-la conforme necessário.
trait Saudavel {
fn calorias(&self) -> u32 {
100 // valor padrão
}
}
struct Fruta;
impl Saudavel for Fruta {
// pode usar o padrão ou sobrescrever
}
Conclusão
A palavra-chave impl é uma das ferramentas mais poderosas em Rust, pois:
- Permite organizar lógica relacionada a um tipo;
- Permite que tipos participem de comportamentos definidos por traits (polimorfismo);
- Suporta generics, especializações e restrições com
where.
Resumo Tabelado
| Forma de uso | Propósito | Exemplo |
|---|---|---|
impl Tipo | Métodos e funções associadas | impl Pessoa { fn nova(...) } |
impl Trait for Tipo | Implementar comportamento (trait) | impl Display for Pessoa { ... } |
impl<T> Tipo<T> | Suporte a generics | impl<T> Caixa<T> { ... } |
impl<T> ... where ... | Condições para implementação | where T: Display |
default impl | Implementação padrão em traits | fn metodo() { /* default */ } |