Autodesreferência em Rust: como funciona e por que não é mágica
\n\nSe 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\nNo 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\nO que é autodesreferência e para que serve?
\n\nEm 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.
A autodesreferência torna o código limpo, mas é importante entender seus limites e regras exatas para não cair em armadilhas.
\n\nRegras exatas de autodesreferência em Rust
\n\nVamos 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).
Aqui está a sequência de passos que o compilador executa (simplificada):
\n\n- \n
- Passo 1: Tentar encontrar o método para o tipo
T(como está). \n - Passo 2: Se não encontrado — tentar encontrar o método para
&Tou&mut T(tomada de referência). \n - Passo 3: Se não encontrado — aplicar
Deref, ou seja, desreferenciar uma vez (obterUa partir deT). \n - Passo 4: Repetir os passos 1-3 para o novo tipo
U. \n - Passo 5: Se após várias desreferências o método ainda não for encontrado — erro de compilação. \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.
Exemplos: do simples ao complexo
\n\nVamos ver um código que demonstra essas regras em ação.
\n\nExemplo 1: Referência básica
\n\nstruct 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\nAqui, 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.
Exemplo 2: Referência dupla
\n\nfn 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\nO 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
Leia também