En Rust, la palabra clave use no “importa” código en el sentido tradicional de otros lenguajes; su función es crear un alias local para una ruta (path) específica dentro del ámbito (scope) actual. Esto permite evitar la escritura repetitiva de rutas largas y facilita la legibilidad. El sistema de rutas de Rust se basa en tres pilares: crate (la raíz del proyecto), self (el módulo actual) y super (el módulo padre).
El uso de llaves {} permite agrupar múltiples elementos de un mismo módulo, como use std::io::{Read, Write};, lo que mantiene el código limpio. Cuando dos elementos de distintos módulos comparten el mismo nombre, se utiliza la palabra clave as para renombrar uno de ellos, evitando colisiones de nombres. Por ejemplo, si tienes un Procesador en dos módulos distintos, puedes importarlos como ProcesadorA y ProcesadorB.
Un patrón esencial en el diseño de bibliotecas es la reexportación mediante pub use. Esto permite organizar el código internamente en múltiples archivos y submódulos para mantener el orden, pero exponer una API pública plana y coherente hacia el usuario. Sin la reexportación, el usuario de tu librería tendría que conocer tu estructura interna de archivos para acceder a un tipo, lo cual rompe el principio de encapsulamiento.
Se debe evitar el uso de glob imports (use modulo::*) en código de producción. Aunque son convenientes en tests, en la lógica principal introducen ambigüedad: no sabes exactamente qué elementos se han traído y cualquier cambio en la librería original podría introducir colisiones de nombres inesperadas que impidan la compilación.
// Definición de un módulo interno con estructura compleja
mod interna {
pub struct Datos;
pub struct Config;
pub mod utilidades {
pub struct Herramienta;
}
}
// Módulo externo que simula una dependencia con nombres duplicados
mod externa {
pub struct Herramienta;
}
// Módulo de la API pública que organiza y expone lo necesario
pub mod api {
// 1. Reexportación: El usuario verá 'api::Datos' en lugar de 'interna::Datos'
pub use crate::interna::Datos;
// 2. Importación agrupada
use crate::interna::Config;
use crate::interna::utilidades::Herramienta;
// 3. Uso de 'as' para evitar colisiones entre la herramienta interna y la externa
use crate::externa::Herramienta as HerramientaExterna;
use crate::interna::utilidades::Herramienta as HerramientaInterna;
pub fn ejecutar_demo() {
let _d = Datos;
let _he = HerramientaExterna;
let _hi = HerramientaInterna;
println!("Demo ejecutada con éxito");
}
}
// Módulo de pruebas que utiliza 'super'
mod tests {
use super::api::ejecutar_demo;
// Acceso al módulo padre para verificar tipos internos
use super::interna::Datos;
pub fn run_tests() {
ejecutar_demo();
let _d = Datos;
println!("Tests completados");
}
}
fn main() {
api::ejecutar_demo();
tests::run_tests();
}
Explicación del Código
pub use crate::interna::Datos;: Dentro del móduloapi, estamos reexportando el tipoDatos. Esto permite que cualquier usuario de este crate acceda aapi::Datosdirectamente, ocultando la existencia del módulointerna.use crate::interna::Config;: Importación estándar utilizando una ruta absoluta desde la raíz del crate (crate).use crate::externa::Herramienta as HerramientaExterna;: Aquí aplicamos un alias. Como el módulointerna::utilidadestambién tiene unaHerramienta, renombramos la deexternapara evitar que el compilador se confunda.use crate::interna::utilidades::Herramienta as HerramientaInterna;: Similar al caso anterior, creamos un alias para laHerramientainterna para permitir su coexistencia conHerramientaExternaen el mismo ámbito deapi.use super::api::ejecutar_demo;: En el módulotests, utilizamos la palabra clavesuperpara subir un nivel en la jerarquía y acceder al móduloapique reside en el mismo nivel.use super::interna::Datos;: Acceso directo al módulointernamediantesuper, permitiendo que el módulo de pruebas valide la estructura interna del código.api::ejecutar_demo();: Llamada desdemainutilizando la ruta pública definida por la reexportación y la organización de módulos.
N° 76