En Rust, la organización del código se basa en un sistema de módulos jerárquico que permite encapsular la lógica y controlar el acceso a los elementos (funciones, structs, enums, etc.). A diferencia de otros lenguajes donde la inclusión de archivos es automática, en Rust la jerarquía debe ser explícita: el compilador solo reconoce un módulo si ha sido declarado mediante la palabra clave mod. Un módulo puede definirse inline (dentro del mismo archivo) o en un archivo separado; si usas mod matematica, el compilador buscará src/matematica.rs o src/matematica/mod.rs.
La visibilidad es el núcleo de la seguridad de Rust. Por defecto, todos los elementos son privados al módulo donde se definen. Para permitir el acceso externo, se utiliza la palabra clave pub. Sin embargo, Rust ofrece un control granular: pub(crate) permite que un elemento sea visible en todo el crate pero no fuera de él, y pub(super) lo hace visible solo para el módulo padre. Es crucial entender que la visibilidad de un struct no implica la visibilidad de sus campos; un struct puede ser pub, pero sus campos seguirán siendo privados a menos que se marquen explícitamente como pub.
Para navegar por esta estructura, usamos rutas. Las rutas absolutas comienzan desde la raíz del crate con crate::, mientras que las rutas relativas usan self para el módulo actual o super para subir un nivel en la jerarquía.
// Módulo principal definido de forma inline (simulando un archivo src/sistema.rs)
mod sistema {
// Un struct con visibilidad mixta
pub struct Procesador {
pub id: u32, // Público: accesible desde cualquier lugar
modelo: String, // Privado: solo accesible en el módulo 'sistema'
}
impl Procesador {
// Método público para instanciar el struct (constructor)
pub fn nuevo(id: u32, modelo: String) -> Self {
Self { id, modelo }
}
// Método público para leer el campo privado 'modelo'
pub fn obtener_modelo(&self) -> &str {
&self.modelo
}
}
// Módulo anidado
pub mod kernel {
// pub(crate): Visible en todo el proyecto, pero no para usuarios externos al crate
pub(crate) struct Driver {
pub nombre: String,
}
pub fn ejecutar_tarea() {
// Uso de ruta relativa 'super' para acceder a un elemento del módulo padre
let _p = super::Procesador::nuevo(1, "Intel".to_string());
println!("Kernel: Tarea ejecutada.");
}
}
}
// Módulo de prueba para verificar la visibilidad
mod test_modulo {
// Uso de ruta absoluta 'crate' para importar elementos desde la raíz
use crate::sistema::{Procesador, kernel::Driver};
pub fn ejecutar_pruebas() {
// 1. Instanciación mediante constructor público
let mut proc = Procesador::nuevo(10, "AMD".to_string());
// 2. Acceso a campo público 'id'
proc.id = 20;
println!("ID procesador: {}", proc.id);
// 3. Acceso a campo privado 'modelo' (Esto fallaría si se intentara)
// let _ = proc.modelo; // ERROR: field `modelo` is private
// 4. Acceso a método público para leer datos privados
println!("Modelo: {}", proc.obtener_modelo());
// 5. Acceso a item 'pub(crate)'
let _d = Driver { nombre: "Red".to_string() };
// 6. Acceso a función del módulo anidado
sistema::kernel::ejecutar_tarea();
}
}
fn main() {
test_modulo::ejecutar_pruebas();
}
Explicación del Código
mod sistema: Define el módulo base. En un proyecto real, este contenido estaría en un archivo separado.pub struct Procesador: Define un tipo público, pero sus campos tienen reglas distintas.id: u32: Campo público; puede ser modificado desdetest_modulo.modelo: String: Campo privado; solo puede ser accedido por métodos dentro desistema.Procesador::nuevo: Un métodopubque permite la creación de la estructura, actuando como un constructor para manejar la lógica de inicialización de campos privados.Procesador::obtener_modelo: Un métodopubque actúa como “getter”, permitiendo leermodelosin romper el encapsulamiento.mod kernel: Un módulo hijo desistema.pub(crate) struct Driver: Gracias apub(crate), el structDriveres visible dentro detest_moduloporque ambos pertenecen al mismo crate, pero no sería visible si este código fuera una librería usada por otro proyecto.super::Procesador: La palabra clavesupersube un nivel en la jerarquía, permitiendo quekernelvea aProcesador.use crate::sistema::...: La ruta absolutacratesalta directamente a la raíz para buscar la definición desistema.test_modulo::ejecutar_pruebas(): La función principal que orquesta el acceso a todos los niveles de visibilidad probados.
N° 75