IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)

Rust par l'exemple


précédentsommairesuivant

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.

 
Sélectionnez
1.
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).

 
Sélectionnez
1.
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

La généricité et les méthodes.

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.

 
Sélectionnez
1.
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).

 
Sélectionnez
1.
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 :

 
Sélectionnez
1.
2.
3.
4.
5.
6.
7.
$ tree .
.
|-- my
|   |-- inaccessible.rs
|   |-- mod.rs
|   `-- nested.rs
`-- split.rs
 
Sélectionnez
1.
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();
}
 
Sélectionnez
1.
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()`");
}
 
Sélectionnez
1.
2.
3.
4.
5.
// Dans le fichier my/inaccessible.rs
#[allow(dead_code)]
pub fn public_function() {
    println!("called `my::inaccessible::public_function()`");
}
 
Sélectionnez
1.
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()`

précédentsommairesuivant

Licence Creative Commons
Le contenu de cet article est rédigé par Rust Core Team et est mis à disposition selon les termes de la Licence Creative Commons Attribution 3.0 non transposé.
Les logos Developpez.com, en-tête, pied de page, css, et look & feel de l'article sont Copyright © 2013 Developpez.com.