Le système de modules de Rust est en fait incroyablement flexible et vous permettra d'exposer le type de structure que vous souhaitez tout en masquant la structure de votre code dans des fichiers.
Je pense que la clé ici est de l'utiliser pub use
, ce qui vous permettra de réexporter des identifiants à partir d'autres modules. Il existe un précédent pour cela dans la std::io
caisse de Rust où certains types de sous-modules sont réexportés pour être utilisés dansstd::io
.
Edit (2019-08-25): la partie suivante de la réponse a été écrite il y a un certain temps. Il explique comment configurer une telle structure de module avec rustc
seul. Aujourd'hui, on utilise généralement Cargo pour la plupart des cas d'utilisation. Bien que ce qui suit soit toujours valide, certaines parties de celui-ci (par exemple #![crate_type = ...]
) peuvent sembler étranges. Ce n'est pas la solution recommandée.
Pour adapter votre exemple, nous pourrions commencer par cette structure de répertoires:
src/
lib.rs
vector.rs
main.rs
Voici votre main.rs
:
extern crate math;
use math::vector;
fn main() {
println!("{:?}", vector::VectorA::new());
println!("{:?}", vector::VectorB::new());
}
Et votre src/lib.rs
:
#[crate_id = "math"];
#[crate_type = "lib"];
pub mod vector; // exports the module defined in vector.rs
Et enfin 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![] }
}
}
}
Et c'est là que la magie opère. Nous avons défini un sous-module math::vector::vector_a
qui a une implémentation d'un type spécial de vecteur. Mais nous ne voulons pas que les clients de votre bibliothèque se soucient de l'existence d'un vector_a
sous-module. Au lieu de cela, nous aimerions le rendre disponible dans le math::vector
module. Ceci est fait avec pub use self::vector_a::VectorA
, qui réexporte l' vector_a::VectorA
identifiant dans le module courant.
Mais vous avez demandé comment faire cela pour pouvoir mettre vos implémentations vectorielles spéciales dans différents fichiers. C'est ce que fait la mod vector_b;
ligne. Il demande au compilateur Rust de rechercher un vector_b.rs
fichier pour l'implémentation de ce module. Et bien sûr, voici notre src/vector_b.rs
fichier:
#[derive(Debug)]
pub struct VectorB {
xs: Vec<i64>,
}
impl VectorB {
pub fn new() -> VectorB {
VectorB { xs: vec![] }
}
}
Du point de vue du client, le fait que VectorA
et VectorB
soient définis dans deux modules différents dans deux fichiers différents est complètement opaque.
Si vous êtes dans le même répertoire que main.rs
, vous devriez pouvoir l'exécuter avec:
rustc src/lib.rs
rustc -L . main.rs
./main
En général, le chapitre "Crates and Modules" du livre Rust est assez bon. Il existe de nombreux exemples.
Enfin, le compilateur Rust recherche également automatiquement les sous-répertoires. Par exemple, le code ci-dessus fonctionnera inchangé avec cette structure de répertoire:
src/
lib.rs
vector/
mod.rs
vector_b.rs
main.rs
Les commandes à compiler et à exécuter restent également les mêmes.