Autodesreferência em Rust: regras, exemplos e a "mágica" sob o capô

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

Autodesreferência em Rust: como funciona e por que não é mágica

\n\n

Se você já escreveu em Rust, certamente notou que o compilador permite chamar métodos em referências e ponteiros inteligentes como se estivesse trabalhando com o próprio valor. Isso não é mágica nem bug — é um mecanismo estritamente definido chamado autodesreferência (auto-dereferencing).

\n\n

No Stack Overflow, a pergunta «What are Rust's exact auto-dereferencing rules?» acumulou milhares de visualizações — e não à toa. Compreender essas regras transforma o código Rust de um «conjunto de erros estranhos» em uma ferramenta elegante e previsível. Vamos dar uma olhada sob o capô.

\n\n

O que é autodesreferência e para que serve?

\n\n

Em Rust, temos referências (&T, &mut T) e ponteiros inteligentes (Box<T>, Rc<T>, Arc<T>). Quando você escreve my_box.some_method(), o compilador aplica automaticamente a desreferência para acessar o valor interno T. Sem esse mecanismo, você teria que escrever (*my_box).some_method() ou (**my_ref).some_method() — o que rapidamente se torna cansativo e polui o código.

\n\n

A autodesreferência torna o código limpo, mas é importante entender seus limites e regras exatas para não cair em armadilhas.

\n\n

Regras exatas de autodesreferência em Rust

\n\n

Vamos analisar a especificação oficial. Quando o compilador encontra uma expressão do tipo x.method(), ele tenta encontrar um método chamado method para o tipo T, onde T é o tipo de x. Se o método não for encontrado, o compilador inicia o processo de desreferência automática (ou tomada de referência).

\n\n

Aqui está a sequência de passos que o compilador executa (simplificada):

\n\n
    \n
  1. Passo 1: Tentar encontrar o método para o tipo T (como está).
  2. \n
  3. Passo 2: Se não encontrado — tentar encontrar o método para &T ou &mut T (tomada de referência).
  4. \n
  5. Passo 3: Se não encontrado — aplicar Deref, ou seja, desreferenciar uma vez (obter U a partir de T).
  6. \n
  7. Passo 4: Repetir os passos 1-3 para o novo tipo U.
  8. \n
  9. Passo 5: Se após várias desreferências o método ainda não for encontrado — erro de compilação.
  10. \n
\n\n

Importante: o compilador não faz uma cadeia infinita. Ele aplica a desreferência até encontrar o método ou até chegar a um tipo que não implementa Deref.

\n\n

Exemplos: do simples ao complexo

\n\n

Vamos ver um código que demonstra essas regras em ação.

\n\n

Exemplo 1: Referência básica

\n\n
struct Point {\n    x: i32,\n    y: i32,\n}\n\nimpl Point {\n    fn distance_from_origin(&self) -> f64 {\n        ((self.x.pow(2) + self.y.pow(2)) as f64).sqrt()\n    }\n}\n\nfn main() {\n    let p = Point { x: 3, y: 4 };\n    let r = &p; // &Point\n    println!("{}", r.distance_from_origin()); // 5.0\n}
\n\n

Aqui, r é &Point. O método distance_from_origin aceita &self. O compilador vê: r é &Point. Tenta encontrar o método para &Point — encontra! Tudo funciona sem desreferência explícita.

\n\n

Exemplo 2: Referência dupla

\n\n
fn main() {\n    let p = Point { x: 3, y: 4 };\n    let r1 = &p;     // &Point\n    let r2 = &r1;    // &&Point\n    println!("{}", r2.distance_from_origin()); // 5.0\n}
\n\n

O tipo de r2 é &&Point. O compilador tenta encontrar o método para &&Point — não encontra. Tenta tomar uma referência: &&&Point — também não. Em seguida, aplica Deref uma vez: obtém &Point. Para

Blogs

Book Recommendations