En Rust, cuando quieres acceder al valor de una variable sin tomar posesión de ella (es decir, sin mover el ownership), utilizas una referencia inmutable mediante la sintaxis &T. Una referencia es esencialmente un puntero que apunta a una ubicación en memoria donde reside un valor, pero con la garantía de que ese valor no será modificado ni destruido mientras la referencia esté activa.
El uso de referencias inmutables es fundamental para la eficiencia. En lugar de copiar grandes estructuras de datos, simplemente pasas una dirección de memoria. Rust permite tener múltiples referencias inmutables (&T) al mismo tiempo sobre el mismo dato, lo que facilita la lectura concurrente. Sin embargo, existe una regla de oro: si tienes una referencia inmutable activa, no puedes crear una referencia mutable (&mut T) al mismo tiempo para ese mismo valor. Esto evita condiciones de carrera y errores de memoria.
Si intentas usar una referencia que apunta a un valor que ya ha sido liberado (un “puntero colgante”), el compilador de Rust intervendrá. Gracias al Borrow Checker, Rust garantiza que el ciclo de vida (lifetime) de la referencia nunca exceda al ciclo de vida del valor original. Si intentas realizar una operación que viole la propiedad de los datos o la seguridad de la memoria, el programa simplemente no compilará.
// Función que recibe una referencia inmutable a un String
fn mostrar_texto(texto: &String) {
// El parámetro 'texto' es un préstamo (borrow) de la variable original
println!("El contenido es: {}", texto);
}
fn main() {
// 'saludo' es el dueño (owner) del dato en memoria
let saludo = String::from("Hola Rust");
// Creamos múltiples referencias inmutables al mismo valor
let ref1 = &saludo;
let ref2 = &saludo;
let ref3 = &saludo;
// Podemos usar las referencias para llamar a métodos
// Rust aplica "auto-deref" para acceder al método len()
let longitud = &ref1.len();
println!("Longitud detectada: {}", longitud);
// Pasamos las referencias a la función
mostrar_texto(ref1);
mostrar_texto(ref2);
mostrar_texto(ref3);
// El valor 'saludo' sigue siendo válido aquí porque no hubo movimiento (move)
println!("Valor original intacto: {}", saludo);
}
Explicación del Código
let saludo = String::from("Hola Rust");: Se crea una variable de tipoString.saludoes el dueño único de este dato en el heap.let ref1 = &saludo;,ref2,ref3: Mediante el operador&, creamos tres referencias inmutables de tipo&String. Cada una apunta a la misma dirección de memoria desaludo.&ref1.len(): Aquí ocurre una combinación de operaciones. Se llama al método.len()sobreref1. Rust realiza un auto-deref para entender que queremos el método delStringy no del puntero. Al poner&delante, estamos obteniendo una referencia a la longitud.fn mostrar_texto(texto: &String): La función define que no quiere ser dueña de la cadena, sino que solo pide un préstamo temporal (&String). Esto permite que la función sea llamada múltiples veces sin perder el control desaludoenmain.mostrar_texto(ref1);: Se pasa la referenciaref1a la función. El parámetrotextodentro de la función ahora apunta al mismo contenido quesaludo.println!("{}", saludo);: Esta línea es válida porque las referenciasref1,ref2yref3ya no se están usando (su alcance terminó tras las llamadas a la función), permitiendo que el dueño original recupere el control total para la impresión final.
N° 27