9. Les modules▲
Rust fournit un puissant système de modules qui peut être utilisé pour hiérarchiser et diviser logiquement le code en plusieurs sous-modules et gérer la visibilité des ressources (publiques ou privées).
Un module est un ensemble d'éléments (e.g. ensemble de fonctions, de structures, de traits, de blocs « impl » et même d'autres modules).
9-1. La visibilité▲
Par défaut, tout ce qui peut être contenu dans un module est privé. Nous pouvons remédier à cela en utilisant le mot-clé pub
. Seuls les items publics d'un module peuvent être sollicités en dehors du contexte du module.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
43.
44.
45.
46.
47.
48.
49.
50.
51.
52.
53.
54.
55.
56.
57.
58.
59.
60.
61.
62.
63.
64.
65.
66.
67.
68.
69.
70.
71.
72.
// Un module nommé `my`.
mod
my {
// Les items se trouvant dans le module sont privés, par défaut.
fn
private_function() {
println!
("called `my::private_function()`"
);
}
// Utilisez le mot-clé `pub` pour modifier la visibilité par défaut.
pub
fn
function() {
println!
("called `my::function()`"
);
}
// Des items se trouvant dans le même module peuvent se solliciter
// entre-eux, même lorsqu'ils sont privés.
pub
fn
indirect_access() {
print!
("called `my::indirect_access()`, that
\n
> "
);
private_function();
}
// Les modules peuvent également être imbriqués.
pub
mod
nested {
pub
fn
function() {
println!
("called `my::nested::function()`"
);
}
#[allow(dead_code)]
fn
private_function() {
println!
("called `my::nested::private_function()`"
);
}
}
// Les modules imbriqués suivent les mêmes règles vis-à-vis de la
// visibilité.
mod
private_nested {
#[allow(dead_code)]
pub
fn
function() {
println!
("called `my::private_nested::function()`"
);
}
}
}
fn
function() {
println!
("called `function()`"
);
}
fn
main() {
// Les noms des modules rattachés à une ressource peuvent être explicités
// pour supprimer toute ambiguïté entre deux ressources possédant le même
// nom.
function();
my::function();
// Les items publics, y compris ceux qui se trouvent dans les modules
// imbriqués, peuvent être sollicités en dehors du module parent.
my::indirect_access();
my::nested::function();
// Les items privés d'un module ne peuvent pas être directement sollicités,
// même si ils sont imbriqués dans un module public:
// Erreur! `private_function` est privée.
// my::private_function();
// TODO ^ Essayez de décommenter cette ligne.
// Erreur! `private_function` est privée.
// my::nested::private_function();
// TODO ^ Essayez de décommenter cette ligne.
// Erreur! `private_nested` est un module privé.
// my::private_nested::function();
// TODO ^ Essayez de décommenter cette ligne.
}
9-2. La visibilité des structures▲
Les structures disposent d'un niveau supplémentaire de visibilité dédié à leurs champs. Comme pour les autres ressources, les champs d'une structure sont privés par défaut, mais peuvent être rendus publics en utilisant, encore une fois, le mot-clé pub
. La visibilité des champs ne s'applique, bien entendu, que lorsqu'une structure est sollicitée en dehors du module où elle a été déclarée et a pour but de masquer les données (encapsulation).
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
43.
44.
45.
mod
my {
// Une structure publique avec un champ public générique de type `T`.
pub
struct
WhiteBox<T> {
pub
contents: T,
}
// Une structure publique avec un champ privé générique de type `T`.
#[allow(dead_code)]
pub
struct
BlackBox<T> {
contents: T,
}
impl
<T> BlackBox<T> {
// Constructeur public.
pub
fn
new(contents: T) -> BlackBox<T> {
BlackBox {
contents: contents,
}
}
}
}
fn
main() {
// Les structures publiques possédant des champs publics
// peuvent être instanciées avec les séparateurs `{}`.
let
white_box = my::WhiteBox { contents: "public information"
};
// et leurs champs peuvent être sollicités normalement.
println!
("The white box contains:
{}
"
, white_box.contents);
// Les structures publiques composées de champs privés ne peuvent pas être
// instanciées de manière "classique" (i.e. en précisant le nom des champs).
// Erreur! `BlackBox` possèdent des champs privés.
// let black_box = my::BlackBox { contents: "classified information" };
// TODO ^ Essayez de décommenter cette ligne.
// En revanche, elles peuvent être créées avec un constructeur public.
let
_black_box = my::BlackBox::new("classified information"
);
// Les champs privés d'une structure publique ne peuvent pas être
// sollicités directement.
// Erreur! Le champ `contents` est privé.
// println!("The black box contains: {}", _black_box.contents);
// TODO ^ Essayez de décommenter cette ligne.
}
Voir aussi
9-3. La déclaration use▲
La déclaration use
peut être utilisée pour assigner un chemin à un nouveau nom, pour y accéder plus rapidement.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
// Assigne le chemin `deeply::nested::function` à l'identificateur
// `other_function`.
use
deeply::nested::function as
other_function;
fn
function() {
println!
("called `function()`"
);
}
mod
deeply {
pub
mod
nested {
pub
fn
function() {
println!
("called `deeply::nested::function()`"
)
}
}
}
fn
main() {
// Accès moins verbeux à `deeply::nested::function`.
other_function();
println!
("Entering block"
);
{
// Ceci est équivalent à `use deeply::nested::function as function`.
// La nouvelle assignation `function()` prendra le pas
// sur `deeply::nested::function()`.
use
deeply::nested::function;
function();
// Les assignations `use` ne sont disponibles que dans le contexte
// où elles ont vu le jour. Dans ce cas, où `function()` occulte
// le chemin de base, ce "shadowing" n'est effectif que dans ce bloc.
println!
("Leaving block"
);
}
function();
}
9-4. Les mot-clés super et self▲
Les mot-clés super et self
peuvent être utilisés pour lever l'ambiguïté sur la provenance d'une ressource et éviter de réécrire leur chemin respectif(i.e. le chemin de la ressource).
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
43.
44.
45.
46.
47.
48.
49.
50.
51.
52.
53.
54.
55.
56.
fn
function() {
println!
("called `function()`"
);
}
mod
cool {
pub
fn
function() {
println!
("called `cool::function()`"
);
}
}
mod
my {
fn
function() {
println!
("called `my::function()`"
);
}
mod
cool {
pub
fn
function() {
println!
("called `my::cool::function()`"
);
}
}
pub
fn
indirect_call() {
// Appelons toutes les fonctions nommées `fonction` depuis ce
// contexte!
print!
("called `my::indirect_call()`, that
\n
> "
);
// Le mot-clé `self` fait référence au module courant (en l'occurrence
// `my`). Appeler `self::function()` ou `function()` revient exactement
// au même, puisqu'ils font tous deux référence à la même fonction.
self
::function();
function();
// Vous pouvez également utiliser `self` pour accéder à un autre module
// imbriqué dans `my`.
self
::cool::function();
// Le mot-clé `super` fait référence au contexte parent (en-dehors du
// module `my`, pour cet exemple).
super::function();
// Si vous ne spécifiez aucun des deux mot-clés, le compilateur
// comprendra que vous essayez d'utiliser une ressource se trouvant
// dans le contexte de la crate.
// On va donc assigner un nouvel identificateur à `cool::function()` se
// trouvant dans le contexte de la crate.
// Le contexte de la crate représente tout ce qui se trouve en-dehors des modules.
{
use
cool::function as
root_function;
root_function();
}
}
}
fn
main() {
my::indirect_call();
}
9-5. La hiérarchie des fichiers▲
Il est possible de transformer nos modules en un ensemble de fichiers et de répertoires. Recréons l'exemple utilisé pour illustrer le concept de la visibilité en un ensemble de fichiers :
2.
3.
4.
5.
6.
7.
$
tree .
.
|
-- my
|
|
-- inaccessible.rs
|
|
-- mod.rs
|
`-- nested.rs
`
-- split.rs
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
// Dans le fichier my/mod.rs
// De la même manière `mod inaccessible` et `mod nested` vont essayer de localiser
// les fichiers `nested.rs` et `inaccessible.rs` pour récupérer et ajouter leur contenu
// dans leur module respectif.
mod
inaccessible;
pub
mod
nested;
pub
fn
function() {
println!
("called `my::function()`"
);
}
fn
private_function() {
println!
("called `my::private_function()`"
);
}
pub
fn
indirect_access() {
print!
("called `my::indirect_access()`, that
\n
> "
);
private_function();
}
2.
3.
4.
5.
6.
7.
8.
9.
// Dans le fichier my/nested.rs
pub
fn
function() {
println!
("called `my::nested::function()`"
);
}
#[allow(dead_code)]
fn
private_function() {
println!
("called `my::nested::private_function()`"
);
}
2.
3.
4.
5.
// Dans le fichier my/inaccessible.rs
#[allow(dead_code)]
pub
fn
public_function() {
println!
("called `my::inaccessible::public_function()`"
);
}
2.
3.
4.
5.
6.
$
rustc split.rs &&
./split
called `my::function()`
called `function()`
called `my::indirect_access()`
, that
>
called `my::private_function()`
called `my::nested::function()`