Reputation: 38691
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.
Upvotes: 16
Views: 11450
Reputation: 39
The question seems have gone further to "Is it possible to avoid both mod.rs
and <directory>.rs
" or "if neither exist but ./<directory>
(or ./<directory>/<file>
) exists, why not then treat mod name;
as the same as if we had an empty ./<directory>/mod.rs.
" as @allidoiswin has mentioned.
Such a file was probably unavoidable. This could be because a directory only indicates the presence of a node in the module tree and does not describe the node. However, mod
in a .rs
file can fully describe the information of the node(e.g. functions in the mod, the visibility of the submodule).
Suppose we want to move the mod house
in main.rs
to a directory.
.
└── main.rs
// main.rs
mod house {
mod guest {}
pub mod host {
pub fn clean() {
super::clean_house();
}
}
fn clean_house() {
println!("Cleaned!");
}
}
So we make the directory this way and want to avoid house.rs
.
.
├── house
│ ├── guest.rs
│ └── host.rs
└── main.rs
// main.rs
mod house;
fn main() {
house::host::clean();
}
// host.rs
pub fn clean() {
super::clean_house();
}
But we found no where to write the the clean_house()
function and give visibility to mod host
, because house
is a directory rather than a rust code file.
And the solution is to add a house.rs
file, which provides the extra information of the directory house
.
.
├── house
│ ├── guest.rs
│ └── host.rs
├── house.rs
└── main.rs
// house.rs
mod guest;
pub mod host;
fn clean_house() {
println!("Cleaned!");
}
If we consider that house
and house.rs
are co-active, and that the house
directory is where submodules of house.rs
are stored, then there may be some consistency.
Upvotes: -1
Reputation: 759
Add a Path attribute
It is exactly like you mention in your question, but with a small annotation. This example should show how to do that:
Using the same directory structure as in the OP question:
src/
models/
login.rs
routes/
login_route.rs
services/
login_service.rs
main.rs
The main.rs
file can declare the modules as follows:
#[path = "models/login.rs"]
mod models;
#[path = "routes/login_route.rs"]
mod routes;
#[path = "services/login_service.rs"]
mod services;
The Pros of this approach is that your mod <module_name>
need not be the same as the original file or directory -- allowing for shorter names when needed.
The Con, however, is that this won't be able to refer to multiple modules in the subdirectory. (For example, if the models/
directory had more modules inside of it, it becomes a problem.)
Upvotes: 2
Reputation: 60051
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.rs
Simply 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.
Upvotes: 24
Reputation: 15683
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.rs
orfoo/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.rs
is lifted.foo.rs
can 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
.
Upvotes: 6