Les paquets et les crates

La première partie du système de modules que nous allons aborder concerne les paquets et les crates. Une crate est un binaire ou une bibliothèque. Pour la compiler, le compilateur Rust part d'un fichier source, la racine de la crate, à partir duquel est alors créé le module racine de votre crate (nous verrons les modules plus en détail dans la section suivante). Un paquet se compose d'une ou plusieurs crates qui fournissent un ensemble de fonctionnalités. Un paquet contient un fichier Cargo.toml qui décrit comment construire ces crates.

Il y a plusieurs règles qui déterminent ce qu'un paquet peut contenir. Il doit contenir au maximum une seule crate de bibliothèque. Il peut contenir autant de crates binaires que vous le souhaitez, mais il doit contenir au moins une crate (que ce soit une bibliothèque ou un binaire).

Découvrons ce qui se passe quand nous créons un paquet. D'abord, nous utilisons la commande cargo new :

$ cargo new mon-projet
     Created binary (application) `mon-projet` package
$ ls mon-projet
Cargo.toml
src
$ ls mon-projet/src
main.rs

Lorsque nous avons saisi la commande, Cargo a créé un fichier Cargo.toml, qui définit un paquet. Si on regarde le contenu de Cargo.toml, le fichier src/main.rs n'est pas mentionné car Cargo obéit à une convention selon laquelle src/main.rs est la racine de la crate binaire portant le même nom que le paquet. De la même façon, Cargo sait que si le dossier du paquet contient src/lib.rs, alors le paquet contient une crate de bibliothèque qui a le même nom que le paquet, et que src/lib.rs est sa racine. Cargo transmet les fichiers de la crate racine à rustc pour compiler la bibliothèque ou le binaire.

Dans notre cas, nous avons un paquet qui contient uniquement src/main.rs, ce qui veut dire qu'il contient uniquement une crate binaire qui s'appelle mon-projet. Si un paquet contient src/main.rs et src/lib.rs, il a deux crates : une binaire et une bibliothèque, chacune avec le même nom que le paquet. Un paquet peut avoir plusieurs crates binaires en ajoutant des fichiers dans le répertoire src/bin : chaque fichier sera une crate séparée.

Une crate regroupe plusieurs fonctionnalités associées ensemble dans une portée afin que les fonctionnalités soient faciles à partager entre plusieurs projets. Par exemple, la crate rand que nous avons utilisée dans le chapitre 2 nous permet de générer des nombres aléatoires. Nous pouvons utiliser cette fonctionnalité dans notre propre projet en important la crate rand dans la portée de notre projet. Toutes les fonctionnalités fournies par la crate rand sont accessibles via le nom de la crate, rand.

Ranger une fonctionnalité d'une crate dans sa propre portée clarifie si une fonctionnalité précise est définie dans notre crate ou dans la crate rand et évite ainsi de potentiels conflits. Par exemple, la crate rand fournit un trait qui s'appelle Rng. Nous pouvons nous aussi définir une structure qui s'appelle Rng dans notre propre crate. Comme les fonctionnalités des crates sont dans la portée de leur propre espace de nom, quand nous ajoutons rand en dépendance, il n'y a pas d'ambiguïté pour le compilateur sur le nom Rng. Dans notre crate, il se réfère au struct Rng que nous avons défini. Nous accédons au trait Rng de la crate rand via rand::Rng.

Poursuivons et parlons maintenant du système de modules !