Perguntas avançadas de entrevista sobre Rust: análise e exemplos

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

Como passar em uma entrevista sobre Rust: principais perguntas de nível avançado



Rust é uma das linguagens de programação de sistemas mais requisitadas, e a demanda por desenvolvedores sêniores continua crescendo. Se você já domina a sintaxe básica e o sistema de propriedade, na entrevista encontrará perguntas que testam uma compreensão profunda de código unsafe, assincronicidade, tempos de vida complexos e metaprogramação. Neste artigo, analisaremos os tópicos principais e forneceremos exemplos de código para ajudá-lo a passar na entrevista com confiança.



1. Unsafe Rust: quando e por quê?



Uma das perguntas mais comuns em entrevistas avançadas é: "Explique quando você usaria unsafe e quais garantias são violadas".



A resposta deve incluir as quatro principais capacidades que o unsafe oferece:



  • Desreferenciar ponteiros brutos (*const T e *mut T)
  • Chamar funções unsafe (por exemplo, FFI)
  • Acessar variáveis estáticas mutáveis
  • Implementar traits unsafe


Exemplo: implementação de um array dinâmico simples com gerenciamento manual de memória.



use std::alloc::{alloc, dealloc, Layout};use std::ptr;

struct MyVec { ptr: *mut i32, len: usize, cap: usize,}

impl MyVec { fn new() -> Self { MyVec { ptr: ptr::null_mut(), len: 0, cap: 0, } }

fn push(&mut self, val: i32) { if self.len == self.cap { let new_cap = if self.cap == 0 { 1 } else { self.cap * 2 }; let new_layout = Layout::array::<i32>(new_cap).unwrap(); let new_ptr = unsafe { alloc(new_layout) as *mut i32 }; // copiar dados antigos unsafe { ptr::copy_nonoverlapping(self.ptr, new_ptr, self.len); if !self.ptr.is_null() { let old_layout = Layout::array::<i32>(self.cap).unwrap(); dealloc(self.ptr as *mut u8, old_layout); } } self.ptr = new_ptr; self.cap = new_cap; } unsafe { ptr::write(self.ptr.add(self.len), val); } self.len += 1; }}

impl Drop for MyVec { fn drop(&mut self) { if !self.ptr.is_null() { unsafe { let layout = Layout::array::<i32>(self.cap).unwrap(); dealloc(self.ptr as *mut u8, layout); } } }}


Dica: sempre enfatize que unsafe não é desabilitar verificações, mas assumir a responsabilidade pelos invariantes.



2. Lifetimes e variância: como o compilador verifica referências



Em nível avançado, pedirão que você explique o que é variância (covariância, contravariância, invariância) no contexto de tempos de vida. Isso é a chave para entender por que alguns tipos não compilam.



  • Covariância: &'a T — se 'a for maior que 'b, então &'a T pode ser usado como &'b T.
  • Contravariância: fn(T) — se 'a for maior que 'b, então fn(&'b T) pode ser usado como fn(&'a T).
  • Invariância: &mut T — o tempo de vida deve corresponder exatamente.


Exemplo: por que o código a seguir não compila?



fn foo<'a>(x: &'a mut &'a str, y: &'a str) {    *x = y;}

fn main() { let mut s = "hello"; let r = &s; foo(&mut s, r); // erro!}


Resposta: &mut T é invariante em T, portanto o tempo de vida da referência interna deve corresponder ao tempo de vida da referência externa. O compilador não pode "encurtar" o tempo de vida de r.



3. Async Rust: Pin, Unpin e Future

Blogs

Book Recommendations