ProgramaciónDesarrollador de sistemas Rust

¿Puede una estructura en Rust contener referencias a otros objetos? ¿Cuáles son las restricciones sobre la vida de dichas referencias y qué sucederá si intentas devolver de una función una estructura con períodos de vida incompletos de referencias?

Supere entrevistas con el asistente de IA Hintsage

Respuesta

Las estructuras en Rust pueden almacenar referencias a otros objetos mediante la especificación de tiempos de vida explícitos (lifetimes) en la definición de la estructura. Esto es necesario para que el compilador pueda verificar que ninguna referencia se volverá inválida. Aquí hay un ejemplo:

struct Book<'a> { title: &'a str, author: &'a str, }

Aquí la estructura Book contiene dos referencias con el mismo tiempo de vida 'a. Cuando escribes una función que devuelve tal estructura, debes garantizar que todas las referencias dentro de ella serán válidas independientemente de la lógica interna de la función:

fn book_factory<'a>(title: &'a str, author: &'a str) -> Book<'a> { Book { title, author } }

Si intentas devolver de una función una estructura cuyos campos de referencia apuntan, por ejemplo, a variables locales de esa función, ocurrirá un error de compilación, ya que los tiempos de vida de las referencias son insuficientes para un acceso seguro.

Pregunta capciosa

¿Se puede crear una estructura que contenga en uno de sus campos una referencia (&str) y en otro un String? ¿Por qué podría ser un problema?

Una respuesta errónea común: "Sí, se puede, es seguro".

De hecho, si &str se obtiene de un String y la estructura sobrevive a este String, la referencia se volverá colgante (dangling reference). Por ejemplo:

struct Test<'a> { s1: &'a str, s2: String, } fn main() { let s = String::from("hello"); let t = Test { s1: &s, s2: s }; // t.s1 es, en realidad, seguro solo mientras s2 (s) esté vivo, pero si s2 se elimina primero — error }

Ejemplos de errores reales debido al desconocimiento de las sutilezas del tema


Historia En un proyecto, intentaron devolver de una función de carga una estructura que contenía una referencia a una cadena temporal, creada dentro de la misma función. El código no pudo compilarse y se requirió una reescritura significativa para eliminar la vida útil de la variable local.


Historia Un desarrollador pretendía usar una estructura con una referencia a un elemento de un arreglo creado en la función, pero después de devolverla, esta referencia resultó ser inválida, lo que el compilador previno exitosamente.


Historia En un proyecto corporativo, los desarrolladores almacenaron una referencia &str a una cadena de otro objeto, que fue eliminada de la colección antes que la propia referencia; al posterior acceso a esta referencia ocurrió un panic.