Preguntas avanzadas de entrevista sobre Rust: análisis y ejemplos

Entrenador de Python en Línea para Principiantes

Aprende Python fácilmente sin sobrecargarte de teoría. Resuelve tareas prácticas con verificación automática, recibe pistas y escribe código directamente en el navegador, sin instalar nada.

Start Course

Cómo aprobar una entrevista sobre Rust: las mejores preguntas de nivel avanzado



Rust es uno de los lenguajes de programación de sistemas más demandados, y la necesidad de desarrolladores senior sigue creciendo. Si ya dominas la sintaxis básica y el sistema de propiedad, en la entrevista te esperan preguntas que evalúan una comprensión profunda del código unsafe, la asincronía, los lifetimes complejos y la metaprogramación. En este artículo, analizaremos los temas clave y proporcionaremos ejemplos de código que te ayudarán a superar la entrevista con confianza.



1. Unsafe Rust: ¿cuándo y por qué?



Una de las preguntas más frecuentes en una entrevista avanzada es: «Explica cuándo usarías unsafe y qué garantías se infringen».



La respuesta debe incluir las cuatro capacidades principales que proporciona unsafe:



  • Desreferenciar punteros crudos (*const T y *mut T)
  • Llamar a funciones unsafe (por ejemplo, FFI)
  • Acceder a variables estáticas mutables
  • Implementar traits unsafe


Ejemplo: implementación de un array dinámico simple con gestión manual de memoria.



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 }; // copiamos los datos antiguos 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); } } }}


Consejo: siempre enfatiza que unsafe no es desactivar las comprobaciones, sino asumir la responsabilidad de los invariantes.



2. Lifetimes y variance: cómo el compilador verifica las referencias



A nivel avanzado, te pedirán que expliques qué es variance (covarianza, contravarianza, invarianza) en el contexto de los lifetimes. Esta es la clave para entender por qué algunos tipos no compilan.



  • Covarianza: &'a T — si 'a es mayor que 'b, entonces &'a T se puede usar como &'b T.
  • Contravarianza: fn(T) — si 'a es mayor que 'b, entonces fn(&'b T) se puede usar como fn(&'a T).
  • Invarianza: &mut T — el lifetime debe coincidir exactamente.


Ejemplo: ¿por qué el siguiente código no 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); // ¡error!}


Respuesta: &mut T es invariante respecto a T, por lo que el lifetime de la referencia interna debe coincidir con el lifetime de la externa. El compilador no puede «acortar» el lifetime de r.



3. Async Rust: Pin, Unpin y Future

Blogs

Book Recommendations