¿Qué es un recolector de basura y por qué Rust lo rechazó?
\n\nSi vienes del mundo de Python, Java o C#, estás acostumbrado a que la memoria sea gestionada por un recolector de basura (Garbage Collector, GC). Es un "limpiador" invisible que verifica periódicamente qué objetos ya no se utilizan y libera la memoria que ocupan. ¿Cómodo? Sí. Pero tiene sus matices:
\n\n- \n
- Pausas impredecibles. El GC puede activarse en el momento menos oportuno, cuando tu código procesa una solicitud importante o renderiza un fotograma en un juego. \n
- Sobrecarga de memoria. El GC a menudo requiere memoria adicional para su funcionamiento. \n
- Complejidad en sistemas en tiempo real. En sistemas operativos, controladores o dispositivos integrados, las pausas del GC son inaceptables. \n
Rust propone un enfoque radicalmente diferente. En lugar de un recolector de basura, utiliza un sistema de propiedad (ownership) que funciona en la etapa de compilación. El compilador decide por sí mismo cuándo se debe liberar la memoria y lo hace sin ninguna sobrecarga en tiempo de ejecución. Analicemos cómo funciona.
\n\nSistema de propiedad (Ownership): la base de la gestión de memoria
\n\nEn Rust, cada valor tiene exactamente un propietario: la variable a la que pertenece ese valor. Cuando el propietario sale del ámbito (scope), la memoria se libera automáticamente. Sin recolector de basura, sin conteo de referencias: solo el compilador y reglas estrictas.
\n\nReglas de propiedad en Rust
\n\nEstas son las tres reglas principales que el compilador verifica en la etapa de compilación:
\n\n- \n
- Cada valor en Rust tiene un solo propietario. \n
- Cuando el propietario sale del ámbito, el valor se elimina (drop). \n
- El valor se puede transferir a otro propietario (move) o prestar (borrow). \n
fn main() {\n let s1 = String::from("Hola"); // s1 — propietario de la cadena\n let s2 = s1; // La propiedad se TRANSFIERE a s2 (move)\n // println!("{}", s1); // ¡Error! s1 ya no es propietario de la cadena\n println!("{}", s2); // Ok: s2 es el nuevo propietario\n} // Aquí tanto s1 como s2 salen del ámbito,\n // pero la memoria se libera solo una vez — para s2\n\nEn Python o Java, simplemente crearías otra referencia al objeto y el GC se encargaría de ella más tarde. En Rust, no hay sorpresas: el compilador garantiza que la memoria se liberará exactamente una vez.
\n\nPréstamo (Borrowing): cómo usar datos sin transferir la propiedad
\n\nA menudo necesitamos "tomar prestado" temporalmente el acceso a los datos sin quitárselos al propietario. Para esto, Rust tiene referencias (references). Hay dos tipos:
\n\n- \n
- Referencias inmutables (
&T): se pueden leer los datos, pero no modificarlos. \n - Referencias mutables (
&mut T): se pueden leer y modificar, pero solo si no hay otras referencias activas. \n
fn main() {\n let mut text = String::from("Rust");\n \n let r1 = &text; // referencia inmutable\n let r2 = &text; // otra referencia inmutable — se puede\n println!("{} {}", r1, r2);\n \n let r3 = &mut text; // referencia mutable — funciona, porque r1 y r2 ya no se usan\n r3.push_str(" mola!");\n println!("{}", r3);\n \n // Pero esto no se puede:\n // let r1 = &text;\n // let r3 = &mut text; // ¡Error! No se pueden tener referencias mutable e inmutable simultáneamente\n}\n\nEl compilador de Rust no es solo un analizador estático, es un maestro estricto pero justo. No te dejará dispararte en el pie. Si intentas crear una referencia mutable mientras existen referencias inmutables, obtendrás un error de compilación. Este es el trabajo del borrow checker, el mecanismo que reemplaza al