Introducción: Por qué Rust es un desafío para el entrevistador
Rust es un lenguaje que exige del desarrollador una comprensión profunda de la gestión de memoria, el sistema de tipos y el modelo de concurrencia. Una entrevista sobre Rust no es una prueba de sintaxis, sino un examen de la comprensión de la filosofía del lenguaje. En este artículo, analizaremos las preguntas clave que te pueden hacer en una entrevista, desde los fundamentos de la propiedad hasta temas avanzados como la asincronía. Aprenderás qué respuestas espera el entrevistador y cómo evitar errores típicos.
1. Propiedad, préstamo y tiempos de vida
1.1. ¿Qué es la propiedad (ownership) y cómo funciona?
Es el fundamento de Rust. Cada valor tiene exactamente un propietario. Cuando el propietario sale del ámbito, el valor se elimina. Esto permite evitar la recolección de basura y garantiza la seguridad de la memoria en tiempo de compilación.
fn main() { let s1 = String::from("hola"); let s2 = s1; // s1 se mueve a s2 // println!("{}", s1); // ¡Error! s1 ya no es válido println!("{}", s2); // Funciona}Consejo: Explica la diferencia entre movimiento (move) y copia (copy). Para los tipos que implementan el trait Copy (por ejemplo, los números enteros), no se produce un movimiento: los datos se copian.
1.2. Reglas del préstamo (borrowing)
El préstamo permite usar una referencia a los datos sin transferir la propiedad. Hay dos tipos de referencias:
- Inmutables (&T): puede haber tantas como se quiera, los datos no se pueden modificar.
- Mutables (&mut T): solo una referencia a los datos en el ámbito actual.
fn main() { let mut s = String::from("hello"); let r1 = &s; // referencia inmutable let r2 = &s; // otra referencia inmutable — ok // let r3 = &mut s; // ¡Error! No se pueden tener referencias inmutables y mutables simultáneamente println!("{} {}", r1, r2);}Pregunta capciosa: "¿Por qué Rust prohíbe tener referencias mutables e inmutables al mismo tiempo?" Respuesta: para prevenir las condiciones de carrera (data races) en tiempo de compilación.
1.3. Tiempos de vida (lifetimes) — cómo explicarlos en palabras sencillas
Los tiempos de vida son anotaciones que le indican al compilador cuánto tiempo serán válidas las referencias. La mayoría de las veces el compilador los deduce por sí mismo, pero en funciones complejas hay que indicarlos explícitamente.
fn longest<'a>(x: &'a str, y: &'a str) -> &'a str { if x.len() > y.len() { x } else { y }}Idea clave: 'a significa que la referencia devuelta no vivirá más que ambas referencias de entrada. Esto garantiza que la referencia no se convierta en colgante (dangling).
2. Enumeraciones, coincidencia de patrones y traits
2.1. Enum en Rust — por qué es más potente que en otros lenguajes
En Rust, las enumeraciones pueden almacenar datos de cualquier tipo: cadenas, números, estructuras e incluso otras enumeraciones. Esto permite crear tipos de datos algebraicos (ADT).
enum Message { Quit, Move { x: i32, y: i32 }, Write(String), ChangeColor(i32, i32, i32),}Pregunta típica: "¿Cómo funciona Option<T> y por qué Rust no tiene null?" Respuesta: Option es un enum que puede ser Some(T) o None. El compilador obliga a manejar ambas variantes, lo que elimina los errores de puntero nulo.
2.2. Coincidencia de patrones (pattern matching)
La construcción match es el corazón de Rust. Debe ser exhaustiva.
fn describe_point(point: (i32, i32)) -> &'static str { match point { (0, 0) => "origen de coordenadas", (0, _) => "en el eje X", (_, 0) => "en el eje Y", _ => "en algún lugar del plano", }}Truco para la entrevista: Usa if let para