El sistema de módulos de Rust es realmente increíblemente flexible y le permitirá exponer cualquier tipo de estructura que desee mientras oculta cómo se estructura su código en archivos.
Creo que la clave aquí es hacer uso de pub use
, lo que le permitirá reexportar identificadores de otros módulos. Hay un precedente para esto en la std::io
caja de Rust, donde algunos tipos de submódulos se reexportan para su uso enstd::io
.
Editar (2019-08-25): la siguiente parte de la respuesta se escribió hace bastante tiempo. Explica cómo configurar una estructura de módulo de este tipo con rustc
solo. Hoy en día, normalmente se usa Cargo para la mayoría de los casos de uso. Si bien lo siguiente sigue siendo válido, algunas partes (por ejemplo #![crate_type = ...]
) pueden parecer extrañas. Ésta no es la solución recomendada.
Para adaptar su ejemplo, podríamos comenzar con esta estructura de directorio:
src/
lib.rs
vector.rs
main.rs
Aquí está tu main.rs
:
extern crate math;
use math::vector;
fn main() {
println!("{:?}", vector::VectorA::new());
println!("{:?}", vector::VectorB::new());
}
Y tu src/lib.rs
:
#[crate_id = "math"];
#[crate_type = "lib"];
pub mod vector; // exports the module defined in vector.rs
Y finalmente src/vector.rs
:
// exports identifiers from private sub-modules in the current
// module namespace
pub use self::vector_a::VectorA;
pub use self::vector_b::VectorB;
mod vector_b; // private sub-module defined in vector_b.rs
mod vector_a { // private sub-module defined in place
#[derive(Debug)]
pub struct VectorA {
xs: Vec<i64>,
}
impl VectorA {
pub fn new() -> VectorA {
VectorA { xs: vec![] }
}
}
}
Y aquí es donde ocurre la magia. Hemos definido un submódulo math::vector::vector_a
que tiene alguna implementación de un tipo especial de vector. Pero no queremos que a los clientes de su biblioteca les importe que haya un vector_a
submódulo. En cambio, nos gustaría que esté disponible en el math::vector
módulo. Esto se hace con pub use self::vector_a::VectorA
, que reexporta el vector_a::VectorA
identificador en el módulo actual.
Pero preguntaste cómo hacer esto para poder poner tus implementaciones vectoriales especiales en diferentes archivos. Esto es lo que hace la mod vector_b;
línea. Indica al compilador de Rust que busque un vector_b.rs
archivo para la implementación de ese módulo. Y efectivamente, aquí está nuestro src/vector_b.rs
archivo:
#[derive(Debug)]
pub struct VectorB {
xs: Vec<i64>,
}
impl VectorB {
pub fn new() -> VectorB {
VectorB { xs: vec![] }
}
}
Desde la perspectiva del cliente, el hecho de que VectorA
y VectorB
estén definidos en dos módulos diferentes en dos archivos diferentes es completamente opaco.
Si está en el mismo directorio que main.rs
, debería poder ejecutarlo con:
rustc src/lib.rs
rustc -L . main.rs
./main
En general, el capítulo "Cajas y módulos" del libro de Rust es bastante bueno. Hay muchos ejemplos.
Finalmente, el compilador de Rust también busca en subdirectorios automáticamente. Por ejemplo, el código anterior funcionará sin cambios con esta estructura de directorio:
src/
lib.rs
vector/
mod.rs
vector_b.rs
main.rs
Los comandos para compilar y ejecutar siguen siendo los mismos.