I read the mod document and found that I must add mod.rs in each folder, for example I have to define mod like this in my project structure:
src/
models/
login.rs
mod.rs
routes/
login_route.rs
mod.rs
services/
login_service.rs
mod.rs
main.rs
and use it like this in main.rs:
mod models;
mod routes;
mod services;
Why do it like that? Why design like that? If the project increase, the project has many mod.rs file just for expose mod? It is a good practice? I did not understand. What is the advantage about do it like this way? If we just do it like this way:
crate::models::login;
it is so clear and easy to understand.
Some of this is explained in What is the purpose of a mod.rs file?
Essentially Rust does not make any assumptions about the file structure and won't consider other .rs files without the developer declaring them. Instead it is intended that they use the module system to build up an organizational structure within their code.
While this differs from some other languages, this gives more control to the developer. Since import paths are decoupled the file structure, your modules, structs, functions, etc. can be re-organized and re-exported as necessary. This also allows you to declare exactly what is compiled, which can aid in conditional compilation.
So when does Rust use the file structure? When you declare a module without a body:
mod models;
It will look for a file to use for that module.
from a normal file, like utils.rs for example, it will look for a nested file/directory:
./utils/models.rs
./utils/models/mod.rs
from mod.rs or top-level lib.rs or main.rs (they are special in this regard), it will look for a sibling file/directory:
./models.rs
./models/mod.rs
The use of mod.rs conceptually allows you to use a directory as if it were a file (it is similar to index.js if you're familiar with Javascript).
mod.rs files?There are two decent alternatives:
models.rs instead of models/mod.rsSimply move your mod.rs files up one level and rename them to match their directory. You do not have to modify contents of main.rs or any file. Your structure could look like this:
src/
models/
login.rs
routes/
login_route.rs
services/
login_service.rs
main.rs
models.rs
routes.rs
services.rs
This is slowly becoming the preferred method[citation needed] since it gives the files more descriptive names.
main.rs:This is a bit unconventional, but nested module declarations will find nested files. You don't need mod.rs anywhere:
src/
models/
login.rs
routes/
login_route.rs
services/
login_service.rs
main.rs
If you declare your modules in main.rs like so:
mod models {
mod login; // this will use ./models/login.rs
}
mod routes {
mod login_route; // this will use ./routes/login_route.rs
}
mod services {
mod login_service; // this will use ./services/login_service.rs
}
This isn't particularly recommended. It may work fine in small projects, but will become unwieldy as your codebase gets larger. You'll probably want to reach for mod.rs or the method shown above as a way keep your code composed.
Lastly, these transitive modules are not just for declaring other files. They're a convenient place to:
Overall, the module system is just another level of abstraction to keep your code well-encapsulated.
Since Rust 2018 edition, the mod.rs file is optional:
In Rust 2015, if you have a sub-module:
// This `mod` declaration looks for the `foo` module in // `foo.rs` or `foo/mod.rs`. mod foo;It can live in
foo.rsorfoo/mod.rs. If it has sub-modules of its own, it must befoo/mod.rs. So a bar sub-module of foo would live atfoo/bar.rs.In Rust 2018 the restriction that a module with sub-modules must be named
mod.rsis lifted.foo.rscan just befoo.rs, and the sub-module is stillfoo/bar.rs. This eliminates the special name, and if you have a bunch of files open in your editor, you can clearly see their names, instead of having a bunch of tabs namedmod.rs.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With