Je veux avoir un module avec plusieurs structures, chacune dans son propre fichier. En utilisant un Math
module comme exemple:
Math/
Vector.rs
Matrix.rs
Complex.rs
Je veux que chaque structure soit dans le même module, que j'utiliserais à partir de mon fichier principal, comme ceci:
use Math::Vector;
fn main() {
// ...
}
Cependant, le système de modules de Rust (qui est un peu déroutant pour commencer) ne fournit pas un moyen évident de le faire. Il semble ne vous permettre d'avoir tout votre module que dans un seul fichier. N'est-ce pas rustique? Sinon, comment dois-je procéder?
foo::bar::Baz
doit être défini dansfoo/bar.rs
oufoo/bar/mod.rs
.Réponses:
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 lastd::io
caisse de Rust où certains types de sous-modules sont réexportés pour être utilisés dansstd::io
.Pour adapter votre exemple, nous pourrions commencer par cette structure de répertoires:
Voici votre
main.rs
:Et votre
src/lib.rs
:Et enfin
src/vector.rs
,: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'unvector_a
sous-module. Au lieu de cela, nous aimerions le rendre disponible dans lemath::vector
module. Ceci est fait avecpub 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 unvector_b.rs
fichier pour l'implémentation de ce module. Et bien sûr, voici notresrc/vector_b.rs
fichier:Du point de vue du client, le fait que
VectorA
etVectorB
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: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:
Les commandes à compiler et à exécuter restent également les mêmes.
la source
math::Vec2
au lieu demath::vector::Vec2
. (c'est-à-dire, même concept mais un module plus profond.)Les règles du module Rust sont:
Le fichier matrix.rs 1 dans le répertoire math n'est que le module
math::matrix
. C'est facile. Ce que vous voyez sur votre système de fichiers, vous le trouvez également dans votre code source. Il s'agit d'une correspondance un à un des chemins de fichiers et des chemins de module 2 .Vous pouvez donc importer une structure
Matrix
avecuse math::matrix::Matrix
, car la structure est à l'intérieur du fichier matrix.rs dans un répertoire math. Pas heureux? Vous préféreriezuse math::Matrix;
beaucoup à la place, n'est-ce pas? C'est possible.math::matrix::Matrix
Réexportez l'identifiant dans math / mod.rs avec:Il y a une autre étape pour que cela fonctionne. Rust a besoin d'une déclaration de module pour charger le module. Ajoutez un
mod math;
dans main.rs. Si vous ne le faites pas, vous obtenez un message d'erreur du compilateur lors de l'importation comme ceci:L'indice est ici trompeur. Il n'y a pas besoin de caisses supplémentaires, sauf bien sûr que vous avez vraiment l'intention d'écrire une bibliothèque séparée.
Ajoutez ceci en haut de main.rs:
La déclaration de module est également nécessaire pour les sous-modules
vector
,matrix
etcomplex
, carmath
doit les charger pour les réexporter. Une réexportation d'un identifiant ne fonctionne que si vous avez chargé le module de l'identifiant. Cela signifie que pour réexporter l'identifiant,math::matrix::Matrix
vous devez écriremod matrix;
. Vous pouvez le faire dans math / mod.rs. Créez donc le fichier avec ce contenu:Aaa et vous avez terminé.
1 Les noms de fichiers source commencent généralement par une lettre minuscule dans Rust. C'est pourquoi j'utilise matrix.rs et non Matrix.rs.
2 Java est différent. Vous déclarez également le chemin avec
package
. C'est redondant. Le chemin est déjà évident à partir de l'emplacement du fichier source dans le système de fichiers. Pourquoi répéter ces informations dans une déclaration en haut du dossier? Bien sûr, il est parfois plus facile de jeter un coup d'œil rapide sur le code source au lieu de trouver l'emplacement du système de fichiers du fichier. Je peux comprendre les gens qui disent que c'est moins déroutant.la source
Les puristes de Rusts m'appelleront probablement un hérétique et détesteront cette solution, mais c'est beaucoup plus simple: faites simplement chaque chose dans son propre fichier, puis utilisez la macro " include! " Dans mod.rs:
De cette façon, vous n'obtenez aucun module imbriqué ajouté et évitez les règles complexes d'exportation et de réécriture. Simple, efficace, sans chichi.
la source
use super::*
). Vous ne pouvez pas masquer le code d'autres fichiers (ce qui est important pour l'utilisation d'abstractions sûres non sécurisées)D'accord, j'ai combattu mon compilateur pendant un moment et je l'ai finalement fait fonctionner (merci à BurntSushi pour l'avoir signalé
pub use
.main.rs:
math / mod.rs:
math / vector.rs
D'autres structures pourraient être ajoutées de la même manière. REMARQUE: compilé avec 0.9, pas master.
la source
mod math;
enmain.rs
couple de votremain
programme avec votre bibliothèque. Si vous voulez que votremath
module soit indépendant, vous devrez le compiler séparément et le lier avecextern crate math
(comme indiqué dans ma réponse). Dans Rust 0.9, il est possible que la syntaxe soit à laextern mod math
place.J'aimerais ajouter ici comment vous incluez les fichiers Rust lorsqu'ils sont profondément imbriqués. J'ai la structure suivante:
Comment y accédez-vous
sink.rs
outoilet.rs
depuismain.rs
?Comme d'autres l'ont mentionné, Rust n'a aucune connaissance des fichiers. Au lieu de cela, il considère tout comme des modules et des sous-modules. Pour accéder aux fichiers dans le répertoire de la salle de bain, vous devez les exporter ou les placer en haut. Pour ce faire, spécifiez un nom de fichier avec le répertoire auquel vous souhaitez accéder et
pub mod filename_inside_the_dir_without_rs_ext
à l'intérieur du fichier.Exemple.
Créez un fichier appelé
bathroom.rs
dans lehome
répertoire:Exportez les noms de fichiers:
Créez un fichier appelé à
home.rs
côté demain.rs
pub mod
le fichier bathroom.rsDans
main.rs
use
les instructions peuvent également être utilisées:Inclure d'autres modules frères (fichiers) dans des sous-modules
Dans le cas où vous souhaitez utiliser
sink.rs
fromtoilet.rs
, vous pouvez appeler le module en spécifiant les mots clésself
ousuper
.Structure finale du répertoire
Vous vous retrouveriez avec quelque chose comme ça:
La structure ci-dessus ne fonctionne qu'à partir de Rust 2018. La structure de répertoires suivante est également valable pour 2018, mais c'est ainsi que 2015 fonctionnait auparavant.
Dans lequel
home/mod.rs
est le même que./home.rs
ethome/bathroom/mod.rs
est le même quehome/bathroom.rs
. Rust a apporté cette modification car le compilateur serait confus si vous incluiez un fichier portant le même nom que le répertoire. La version 2018 (celle illustrée en premier) corrige cette structure.Consultez ce dépôt pour plus d'informations et cette vidéo YouTube pour une explication générale.
Une dernière chose ... évitez les traits d'union! Utilisez
snake_case
plutôt.Note importante
Vous devez placer tous les fichiers vers le haut, même si les fichiers profonds ne sont pas requis par les fichiers de niveau supérieur.
Cela signifie que pour
sink.rs
les découvrirtoilet.rs
, vous devez les barricader en utilisant les méthodes ci-dessus jusqu'àmain.rs
!En d' autres termes, faire
pub mod sink;
ou à l'use self::sink;
intérieurtoilet.rs
vous ne le travail à moins que vous les avez exposé tout le chemin jusqu'àmain.rs
!Par conséquent, n'oubliez pas de placer vos fichiers au sommet!
la source