Introdução: Por que Rust é tão exigente em entrevistas?
Rust é uma linguagem de programação de sistemas conhecida por sua segurança de memória e alto desempenho. O compilador Rust é rigoroso, mas justo: ele não deixará passar um erro de ownership ou uma dangling reference. É por isso que em entrevistas de Rust raramente perguntam sintaxe "de cor". Em vez disso, os entrevistadores testam uma compreensão profunda do modelo de memória, gerenciamento de recursos e código idiomático.
Neste artigo, vamos analisar as 10 principais perguntas mais frequentes em entrevistas para desenvolvedores Rust Júnior e Pleno. Cada pergunta vem acompanhada de uma explicação e um exemplo de código. Se você está se preparando para uma entrevista, este artigo será seu checklist.
1. Ownership e Borrowing
Este é o fundamento do Rust. Sem entender ownership, você não passará na entrevista. O entrevistador pode pedir para explicar a diferença entre String e &str ou perguntar por que um código não compila.
Pergunta: Explique o que é ownership e como funciona a transferência de dados para funções.
Resposta: Em Rust, cada valor tem exatamente um dono. Quando uma variável sai de escopo, o valor é descartado (drop). Passar para uma função significa uma move de ownership, a menos que o tipo implemente a trait Copy.
fn main() { let s1 = String::from("hello"); let s2 = s1; // s1 movido para s2 // println!("{}", s1); // Erro! s1 não possui mais a string println!("{}", s2);}Se você quiser passar dados sem perder ownership, use referências (&):
fn main() { let s1 = String::from("hello"); let len = calculate_length(&s1); // borrowing println!("O comprimento de '{}' é {}.", s1, len);}
fn calculate_length(s: &String) -> usize { s.len()}Pergunta: O que é mutable borrowing e por que só pode haver um?
Resposta: Mutable borrowing (&mut) permite modificar o valor através de uma referência. O compilador garante que existe apenas uma referência mutável em um escopo, para prevenir data races.
fn main() { let mut s = String::from("hello"); let r1 = &mut s; // let r2 = &mut s; // Erro! Não podem existir duas referências mutáveis r1.push_str(", world"); println!("{}", r1);}2. Lifetimes
Lifetimes são o que assusta iniciantes. Na entrevista, pedirão para explicar para que servem as anotações 'a e como o compilador infere lifetimes.
Pergunta: Quando é necessário especificar lifetimes explicitamente?
Resposta: Quando uma função retorna uma referência e o compilador não consegue determinar por conta própria quanto tempo ela viverá. O exemplo clássico é uma função que retorna a string mais longa entre duas:
fn longest<'a>(x: &'a str, y: &'a str) -> &'a str { if x.len() > y.len() { x } else { y }}
fn main() { let string1 = String::from("string longa"); let result; { let string2 = String::from("curta"); result = longest(&string1, &string2); } // println!("{}", result); // Erro! string2 foi descartada, referência dangling}A anotação 'a diz: "o tempo de vida da referência retornada é igual ao menor dos tempos de vida das referências de entrada".
Pergunta: O que é elision (regras de omissão de lifetimes)?
Resposta: O compilador insere lifetimes automaticamente em casos simples. Se uma função recebe uma referência e retorna uma referência — o lifetime é inferido. Se houver múltiplas referências de entrada — é necessário especificar explicitamente.
3. Enum, Pattern Matching e Option/Result
Rust usa ativamente tipos algébricos