O sistema de módulos do Rust é incrivelmente flexível e permite que você exponha qualquer tipo de estrutura que desejar, enquanto oculta como seu código está estruturado em arquivos.
Acho que a chave aqui é fazer uso de pub use
, o que permitirá que você reexporte identificadores de outros módulos. Há precedentes para isso na std::io
caixa de Rust, onde alguns tipos de submódulos são reexportados para uso emstd::io
.
Editar (25/08/2019): a parte seguinte da resposta foi escrita há algum tempo. Ele explica como configurar essa estrutura de módulo rustc
sozinho. Hoje, geralmente se usa Cargo para a maioria dos casos de uso. Embora o seguinte ainda seja válido, algumas partes (por exemplo #![crate_type = ...]
) podem parecer estranhas. Esta não é a solução recomendada.
Para adaptar seu exemplo, podemos começar com esta estrutura de diretório:
src/
lib.rs
vector.rs
main.rs
Aqui está o seu main.rs
:
extern crate math;
use math::vector;
fn main() {
println!("{:?}", vector::VectorA::new());
println!("{:?}", vector::VectorB::new());
}
E seu src/lib.rs
:
#[crate_id = "math"];
#[crate_type = "lib"];
pub mod vector; // exports the module defined in vector.rs
E 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![] }
}
}
}
E é aqui que a mágica acontece. Definimos um submódulo math::vector::vector_a
que tem alguma implementação de um tipo especial de vetor. Mas não queremos que os clientes de sua biblioteca se importem que haja um vector_a
submódulo. Em vez disso, gostaríamos de disponibilizá-lo no math::vector
módulo. Isso é feito com o pub use self::vector_a::VectorA
, que reexporta o vector_a::VectorA
identificador no módulo atual.
Mas você perguntou como fazer isso para que pudesse colocar suas implementações vetoriais especiais em arquivos diferentes. É isso que a mod vector_b;
linha faz. Ele instrui o compilador Rust a procurar um vector_b.rs
arquivo para a implementação desse módulo. E com certeza, aqui está nosso src/vector_b.rs
arquivo:
#[derive(Debug)]
pub struct VectorB {
xs: Vec<i64>,
}
impl VectorB {
pub fn new() -> VectorB {
VectorB { xs: vec![] }
}
}
Do ponto de vista do cliente, o fato de VectorA
e VectorB
serem definidos em dois módulos diferentes em dois arquivos diferentes é totalmente opaco.
Se você estiver no mesmo diretório que main.rs
, deverá ser capaz de executá-lo com:
rustc src/lib.rs
rustc -L . main.rs
./main
Em geral, o capítulo "Caixas e Módulos" no livro Rust é muito bom. Existem muitos exemplos.
Finalmente, o compilador Rust também procura em subdiretórios para você automaticamente. Por exemplo, o código acima funcionará inalterado com esta estrutura de diretório:
src/
lib.rs
vector/
mod.rs
vector_b.rs
main.rs
Os comandos para compilar e executar também permanecem os mesmos.