Il sistema di moduli di Rust è in realtà incredibilmente flessibile e ti consentirà di esporre qualsiasi tipo di struttura desideri nascondendo il modo in cui il tuo codice è strutturato nei file.
Penso che la chiave qui sia da usare pub use
, che ti permetterà di riesportare gli identificatori da altri moduli. C'è un precedente per questo nel std::io
crate di Rust, dove alcuni tipi di sotto-moduli vengono riesportati per l'uso instd::io
.
Modifica (2019-08-25): la parte seguente della risposta è stata scritta parecchio tempo fa. Spiega come impostare una struttura di questo tipo con rustc
solo. Oggi, di solito si usa Cargo per la maggior parte dei casi d'uso. Anche se quanto segue è ancora valido, alcune parti (ad esempio #![crate_type = ...]
) potrebbero sembrare strane. Questa non è la soluzione consigliata.
Per adattare il tuo esempio, potremmo iniziare con questa struttura di directory:
src/
lib.rs
vector.rs
main.rs
Ecco il tuo main.rs
:
extern crate math;
use math::vector;
fn main() {
println!("{:?}", vector::VectorA::new());
println!("{:?}", vector::VectorB::new());
}
E il tuo src/lib.rs
:
#[crate_id = "math"];
#[crate_type = "lib"];
pub mod vector; // exports the module defined in vector.rs
E infine 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![] }
}
}
}
Ed è qui che avviene la magia. Abbiamo definito un sottomodulo math::vector::vector_a
che ha alcune implementazioni di un tipo speciale di vettore. Ma non vogliamo che i clienti della tua libreria si preoccupino della presenza di un vector_a
sottomodulo. Invece, vorremmo renderlo disponibile nel math::vector
modulo. Questo viene fatto con pub use self::vector_a::VectorA
, che riesporta l' vector_a::VectorA
identificatore nel modulo corrente.
Ma hai chiesto come farlo in modo da poter inserire le tue implementazioni vettoriali speciali in file diversi. Questo è ciò mod vector_b;
che fa la linea. Indica al compilatore Rust di cercare un vector_b.rs
file per l'implementazione di quel modulo. E abbastanza sicuro, ecco il nostro src/vector_b.rs
file:
#[derive(Debug)]
pub struct VectorB {
xs: Vec<i64>,
}
impl VectorB {
pub fn new() -> VectorB {
VectorB { xs: vec![] }
}
}
Dal punto di vista del cliente, il fatto che VectorA
e VectorB
siano definiti in due diversi moduli in due file differenti è completamente opaco.
Se ti trovi nella stessa directory di main.rs
, dovresti essere in grado di eseguirlo con:
rustc src/lib.rs
rustc -L . main.rs
./main
In generale, il capitolo "Crates and Modules" nel libro Rust è abbastanza buono. Ci sono molti esempi.
Infine, il compilatore Rust cerca automaticamente anche nelle sottodirectory. Ad esempio, il codice precedente funzionerà invariato con questa struttura di directory:
src/
lib.rs
vector/
mod.rs
vector_b.rs
main.rs
Anche i comandi da compilare ed eseguire rimangono gli stessi.