Introducción: ¿Por qué Rust es tan exigente en las entrevistas?
Rust es un lenguaje de programación de sistemas conocido por su seguridad de memoria y alto rendimiento. El compilador de Rust es estricto pero justo: no dejará pasar un error de ownership (propiedad) o una dangling reference (referencia colgante). Es por eso que en las entrevistas de Rust rara vez preguntan sintaxis "de memoria". En cambio, los entrevistadores evalúan una comprensión profunda del modelo de memoria, la gestión de recursos y el código idiomático.
En este artículo, analizaremos las 10 preguntas principales que se hacen con más frecuencia en entrevistas para desarrolladores Rust Junior y Middle. Cada pregunta viene acompañada de una explicación y un ejemplo de código. Si te estás preparando para una entrevista, este artículo será tu lista de verificación.
1. Ownership (Propiedad) y Borrowing (Préstamo)
Este es el fundamento de Rust. Sin entender la propiedad, no pasarás la entrevista. El entrevistador puede pedirte que expliques la diferencia entre String y &str o preguntarte por qué un código no compila.
Pregunta: Explica qué es la propiedad (ownership) y cómo funciona la transferencia de datos a las funciones.
Respuesta: En Rust, cada valor tiene exactamente un propietario. Cuando una variable sale del ámbito, el valor se elimina (drop). Pasar a una función significa mover (move) la propiedad, a menos que el tipo implemente el trait Copy.
fn main() { let s1 = String::from("hello"); let s2 = s1; // s1 se mueve a s2 // println!("{}", s1); // ¡Error! s1 ya no es propietario del string println!("{}", s2);}Si quieres pasar datos sin perder la propiedad, usa referencias (&):
fn main() { let s1 = String::from("hello"); let len = calculate_length(&s1); // préstamo println!("La longitud de '{}' es {}.", s1, len);}
fn calculate_length(s: &String) -> usize { s.len()}Pregunta: ¿Qué es el préstamo mutable (mutable borrowing) y por qué solo puede haber uno?
Respuesta: El préstamo mutable (&mut) permite cambiar el valor a través de una referencia. El compilador garantiza que solo exista una referencia mutable en el ámbito para prevenir condiciones de carrera (data races).
fn main() { let mut s = String::from("hello"); let r1 = &mut s; // let r2 = &mut s; // ¡Error! No puede haber dos referencias mutables r1.push_str(", world"); println!("{}", r1);}2. Tiempos de vida (Lifetimes)
Los tiempos de vida son lo que asusta a los principiantes. En la entrevista, te pedirán que expliques para qué sirven las anotaciones 'a y cómo el compilador infiere los lifetimes.
Pregunta: ¿Cuándo es necesario especificar explícitamente los tiempos de vida?
Respuesta: Cuando una función devuelve una referencia y el compilador no puede determinar por sí mismo cuánto tiempo vivirá. Un ejemplo clásico es una función que devuelve el string más largo de dos:
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("cadena larga"); let result; { let string2 = String::from("corta"); result = longest(&string1, &string2); } // println!("{}", result); // ¡Error! string2 se eliminó, referencia colgante}La anotación 'a dice: "el tiempo de vida de la referencia devuelta es igual al menor de los tiempos de vida de las referencias de entrada".
Pregunta: ¿Qué es el elision (reglas de omisión de lifetimes)?
Respuesta: El compilador inserta automáticamente los lifetimes en casos simples. Si una función toma una referencia y devuelve una referencia, el lifetime se infiere. Si hay múltiples referencias de entrada, se debe especificar explícitamente.
3. Enum, Pattern Matching y Option/Result
Rust utiliza activamente tipos algebraicos