Cómo superar una entrevista de Rust: top preguntas de nivel avanzado
\n\nRust es un lenguaje de programación de sistemas que está ganando popularidad gracias a su seguridad, rendimiento y ausencia de recolector de basura. Si ya dominas los conceptos básicos y te preparas para una entrevista para un puesto de desarrollador Rust Senior o Middle, te enfrentarás a preguntas que van más allá de la sintaxis simple. En este artículo, analizaremos los temas avanzados clave que suelen aparecer en las entrevistas técnicas.
\n\nVeremos cuatro bloques: ownership y borrowing, lifetimes, código unsafe y macros, y multihilo avanzado. Cada sección contiene preguntas reales y ejemplos de código.
\n\n1. Ownership, borrowing y reglas de mutabilidad
\n\nPregunta: Explica cómo funciona el mecanismo de ownership en Rust. ¿Cuál es la diferencia entre &T, &mut T y Box<T>?
Respuesta: El ownership es la base de la seguridad de memoria en Rust. Cada valor tiene exactamente un propietario. Cuando el propietario sale del ámbito, el valor se destruye. El borrowing (&T) permite "tomar prestada" temporalmente una referencia a los datos sin transferir la propiedad. El borrowing mutable (&mut T) da derecho a modificar los datos, pero solo si no hay otras referencias.
Box<T> es un puntero inteligente que asigna memoria en el heap. Transfiere la propiedad, lo que lo diferencia de las referencias simples.
fn main() {\n let mut s = String::from("Hola");\n let r1 = &s; // referencia inmutable\n let r2 = &mut s; // ¡Error! no se puede tener &mut y & al mismo tiempo\n // println!("{}", r1);\n}\n\n\nPregunta: ¿Qué es la "regla de un solo borrowing mutable"?
\n\nRespuesta: En cualquier momento, un valor puede tener una referencia mutable o cualquier número de referencias inmutables, pero no ambas al mismo tiempo. Esto previene las condiciones de carrera en tiempo de compilación.
\n\n2. Lifetimes: cómo el compilador sabe que una referencia está viva
\n\nPregunta: ¿Por qué son necesarias las anotaciones de lifetimes? Da un ejemplo en el que sean obligatorias.
\n\nRespuesta: Las anotaciones de lifetime ('a, 'b, etc.) ayudan al compilador a verificar que todas las referencias son válidas. Son obligatorias cuando una función devuelve una referencia vinculada a uno de los parámetros de entrada y el compilador no puede inferir el lifetime automáticamente.
// Función que devuelve la cadena más larga\nfn longest<'a>(x: &'a str, y: &'a str) -> &'a str {\n if x.len() > y.len() { x } else { y }\n}\n\nfn main() {\n let s1 = String::from("larga");\n let result;\n {\n let s2 = String::from("corta");\n result = longest(&s1, &s2); // ok\n }\n // println!("{}", result); // Error: s2 ha muerto\n}\n\n\nPregunta: ¿Qué es la "elisión de lifetimes"?
\n\nRespuesta: El compilador agrega automáticamente anotaciones de lifetime en casos simples. Por ejemplo, para el método fn first_word(s: &str) -> &str, el compilador entiende que el lifetime de salida es igual al de entrada. La elisión funciona según tres reglas descritas en el libro de Rust.
3. Unsafe Rust y macros
\n\nPregunta: ¿Cuándo está justificado el uso de unsafe? ¿Qué operaciones solo están disponibles dentro de bloques unsafe?
Respuesta: unsafe se utiliza para operaciones que el compilador no puede verificar: desreferenciar punteros crudos, llamar a funciones externas (FFI), acceder a variables estáticas mutables, implementar traits inseguros. Sin embargo, unsafe no