Skip to main content

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 impl podem 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 usoPropósitoExemplo
impl TipoMétodos e funções associadasimpl Pessoa { fn nova(...) }
impl Trait for TipoImplementar comportamento (trait)impl Display for Pessoa { ... }
impl<T> Tipo<T>Suporte a genericsimpl<T> Caixa<T> { ... }
impl<T> ... where ...Condições para implementaçãowhere T: Display
default implImplementação padrão em traitsfn metodo() { /* default */ }