Discussion du code modules_visibilite
Dans cette partie nous discutons de ce code.
Concepts
Les concepts abordés dans cet exemple sont:
Discussion
Jusqu'ici, tout le code était contenu dans le fichier main.rs
. Au fur et à mesure que le code devient plus complexe et long, il est nécessaire de le séparer en plusieurs fichiers (modules) et de gérer
la visibilité des structures, types énumérés, fonctions, etc. Nous allons voir dans ce chapitre comment
cela se passe pour le Rust. Pour plus d'informations vous pouvez vous référer à La Bible du Rust.
Les modules
Afin de séparer le code en plusieurs fichiers il est nécessaire de créer un fichier lib.rs
qui se trouve dans le même répertoire que le fichier main.rs
. Ce répertoire est en général le répertoire src
de votre projet. Ici c'est dans projet05/src
. Dans notre cas, il contient très peu de lignes
/*!
modules_visibilite illustrates the concepts of **modules** and **visibility**.
*/
// The size of the tab
const SIZE: usize = 9;
pub mod io;
mod minimum;
pub mod something_or_nothing;
La présence d'un fichier lib.rs
indique que vous avez créé une librairie, appelée crate
en Rust.
Toutes les libraries publiées en Rust sont des crate
et peuvent se télécharger depuis le site
crates.io.
On voit qu'il y a dans le fichier lib.rs
la définition de la constante SIZE
, ainsi que trois lignes
contenant le mot-clé mod
qui indique la présence d'un module. Par défaut, le compilateur Rust va aller chercher
le contenu de ces modules dans les fichiers io.rs
, minimum.rs
, et something_or_nothing.rs
(ou io/mod.rs
, minimum/mod.rs
, et something_or_nothing/mod.rs
). Dans ce chapitre, nous avons simplement réparti tout le code qui se trouvait dans main.rs
dans la partie 4. Le mot-clé
pub
indique la visibilité du module à l'intérieur de votre librairie.
Ainsi, le module minimum
n'est pas exposé à vos utilisatrices et utilisateurs, alors que io
et something_or_nothing
le sont. Nous verrons un peu plus bas les règles sur la visibilité.
Afin d'utiliser les fonctions définies dans notre librairie dans notre programme principal (le main.rs
)
comme dans le code suivant
use modules_visibilite::io;
use modules_visibilite::something_or_nothing::find_min;
Pour importer les modules avec la syntaxe suivante
use nom_de_la_crate::nom_du_module;
où le nom_de_la_crate
est défini dans le fichier modules_visibilite/Cargo.toml
(le champs name
),
le nom du module ici est io
et chaque module est séparé par le symbole ::
.
On a également importé la fonction find_min
spécifiquement
avec la syntaxe
use nom_de_la_crate::nom_du_module::nom_de_la_fonction;
Ce n'est pas fait dans cet exemple, mais il est tout à fait possible de définir des sous-modules (voir Le Livre).
Afin d'utiliser de partager des fonctions entre les modules, il faut également les importer comme dans le module something_or_nothing
qui nécessite l'import du trait Minimum
à l'aide de la syntaxe
use crate::minimum::Minimum;
On voit la nécessité d'utiliser le mot-clé crate
pour indiquer que le module est importé depuis
l'intérieur de notre librairie. Puis il faut suivre l'arborescence habituelle avec le module minimum
et le trait Minimum
le tout séparé par des séparateurs, ::
.
Observations
- Observez ce qui se passe si vous commentez la ligne
mod minimum;
danslib.rs
et tentez de compiler le code. Que vous dit le compilateur? - Que se passe-t-il, si vous enlevez le mot clé
pub
de la lignepub mod io;
danslib.rs
et tentez de compiler le code? Quel message s'affiche?
On constate que pour la partie 1
, le compilateur n'est pas content, car il ne trouve pas
le module minimum
dans notre crate
error[E0432]: unresolved import `crate::minimum`
--> src/something_or_nothing.rs:2:12
|
2 | use crate::minimum::Minimum;
| ^^^^^^^ could not find `minimum` in the crate root
For more information about this error, try `rustc --explain E0432`.
error: could not compile `modules_visibilite` (lib) due to previous error
Pour la partie 2
, on a deux messages un peu différents
Compiling modules_visibilite v0.1.0 (/home/orestis/git/projects/rust-101/codes/rust_lang/modules_visibilite)
warning: function `read_command_line` is never used
--> src/io.rs:2:8
|
2 | pub fn read_command_line() -> [i32; crate::SIZE] {
| ^^^^^^^^^^^^^^^^^
|
= note: `#[warn(dead_code)]` on by default
warning: function `print_tab` is never used
--> src/io.rs:8:8
|
8 | pub fn print_tab(tab: &[i32; crate::SIZE]) {
| ^^^^^^^^^
warning: `modules_visibilite` (lib) generated 2 warnings
error[E0603]: module `io` is private
--> src/main.rs:2:13
|
2 | use modules_visibilite::io;
| ^^ private module
|
note: the module `io` is defined here
--> /home/orestis/git/projects/rust-101/codes/rust_lang/modules_visibilite/src/lib.rs:9:1
|
9 | mod io;
| ^^^^^^
For more information about this error, try `rustc --explain E0603`.
error: could not compile `modules_visibilite` (bin "modules_visibilite") due to previous error
Le compilateur commence par nous prévenir par des warnings que les fonctions print_tab
et read_command_line()
ne sont jamais utilisées. Puis, nous avons un message nous prévenant que io
est privé.
Visibilité
Par défaut, Rust rend privées toutes les structures (et ses membres ou fonctions statiques), traits, fonctions, etc. Cela signifie qu'elles ne sont pas visibles en dehors du
module dans lequel elles sont définies. Pour les rendre visibles (en dehors du module dans lequel elles sont définies), il faut les rendre publiques à l'aide du préfixe pub
.
Il y a plusieurs exemples de l'utilisation dans ce chapitre.
- Pour les fonctions:
pub fn print_tab(tab: &[i32; crate::SIZE]) {
for t in tab {
print!("{} ", t);
}
println!();
}
on voit qu'on préfixe pub
devant le mot-clé fn
pour rendre la fonction publique. Si on le retire, le compilateur donnera le message d'erreur suivant
error[E0603]: function `print_tab` is private
--> src/main.rs:11:9
|
11 | io::print_tab(&tab);
| ^^^^^^^^^ private function
|
note: the function `print_tab` is defined here
--> /home/orestis/git/projects/rust-101/codes/rust_lang/modules_visibilite/src/io.rs:9:1
|
9 | fn print_tab(tab: &[i32; crate::SIZE]) {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
For more information about this error, try `rustc --explain E0603`.
- Pour un type énuméré:
#[derive(Clone, Copy)]
pub enum SomethingOrNothing<T> {
Nothing,
Something(T),
}
où on préfixe le mot clé enum
avec un pub
.
- Pour les méthodes
impl<T: std::fmt::Display> SomethingOrNothing<T> {
pub fn print(&self) {
match self {
SomethingOrNothing::Nothing => println!("Nothing."),
SomethingOrNothing::Something(val) => println!("Something is: {}", val),
}
}
}
où comme pour les fonctions, on préfixe fn
avec un pub
.
- Pour les traits:
pub trait Minimum: Copy {
fn min(self, rhs: Self) -> Self;
}
il faut noter que seule la définition du trait a besoin d'être publique. L'implémentation pour un type particulier n'a pas besoin de l'être.
Remarque
Tous les champs d'une structure (même publique) sont privés par défaut. Ainsi une structure Point
contenant les coordonnées d'un points en deux dimension se définit comme
#![allow(unused)] fn main() { pub struct Point { x: f32, y: f32, } }
En dehors du module où cette structure serait définie, il est impossible d'accéder aux champs de la structure.
L'instantiation et initialisation d'un Point
let p = Point { x: 1.0, y: 0.2 };
donnerait une erreur de compilation, car x
et y
sont privés. Il est donc nécessaire de préfixer les champs publics par un pub
pour qu'ils soient accessible en dehors du module.
error[E0451]: field `x` of struct `Point` is private
--> src/main.rs:15:43
|
15 | let p = something_or_nothing::Point { x: 1.0, y: 0.5 };
| ^^^^^^ private field
error[E0451]: field `y` of struct `Point` is private
--> src/main.rs:15:51
|
15 | let p = something_or_nothing::Point { x: 1.0, y: 0.5 };
| ^^^^^^ private field
For more information about this error, try `rustc --explain E0451`.
On aurait pour rendre x
et y
publics besoin de définir la structure comme
#![allow(unused)] fn main() { struct Point { pub x: f32, pub y: f32, } }
Rustlings
Les rustlings à faire dans ce chapitre sont les suivants:
Les modules
$ rustlings run modules1
$ rustlings run modules2
$ rustlings run modules3