The difference is that they do different things. : D
mod
The keyword mod
declaring a module in Rust. Modules are used to control scope and privacy. For an introduction to the concept of modules, see here.
The mod
can be used in two different ways to create modules:
Explicitly defining a block
//# Arquivo `main.rs`
mod math {
pub fn add(a: i64, b: i64) -> i64 { a + b }
pub fn sub(a: i64, b: i64) -> i64 { add(a, -b) }
}
// Podemos utilizar `math::add` e `math::sub` aqui.
Above, we created a new module, qualified as math
. Outside of this module, to use one of its exposed functions, it is necessary to use the module name.
Notice that inside math
, it is possible to refer to the function add
only as add
(as I did to implement the function sub
). But, from outside the module, as said above, it is necessary to use math::add
.
Defining via another file
//# Arquivo `math.rs`
pub fn add(a: i64, b: i64) -> i64 { a + b }
pub fn sub(a: i64, b: i64) -> i64 { add(a, -b) }
And:
//# Arquivo `main.rs`:
mod math;
// Podemos utilizar `math::add` e `math::sub` aqui.
Note that from the perspective of main.rs
, nothing has changed. In it, as in the previous example, a new module has been defined, qualified as math
. The difference is where the contents of the module have been defined.
In this case, where mod
is used without defining a block explicitly, it will create a new module with the given name and search the contents of the module in a file with corresponding name.
Note that the module nay is defined in the file math.rs
. That is, the file math.rs
nay is the definition of a module. This is often a point of confusion in Rust since some languages (such as Javascript) operate differently. The definition of the module occurs in main.rs
, through the directive mod math
.
With this, we can conclude that a module in Rust is created by the directive mod
. The contents of the file can be set directly, with a block following mod <name>
. Can also be set in the file <name>.rs
.
use
The directive use
is, when allied to the mod
, a point of confusion. In many languages (such as Javascript and Python), the concept of modules is usually associated with a single keyword, such as import
. Rust takes a slightly different approach and so it may seem "strange". But it’s actually quite simple. Let’s see...
We have seen that a module can be defined using the keyword mod
. From that moment, we will be able to access the contents of the module using a module path.
In the above examples, main.rs
, the way to get to the function sum
, module math
, is math::sum
. If there were several nested modules (which is common in Rust), it would be something like std::fs::read_to_string
. In this case, it is a function called read_to_string
, inside the module fs
which, in turn, is inside the module std
.
So what’s the point of use
?
I’ll tell you what the use
it is not. The use
is not a mechanism for importing modules. This means that the use
does not serve to bring anything new to the scope. So much so if you try to use use
with something that is not in scope, will give error.
The use
serves to shorten the way member(s) of a module.
Regarding the example of the beginning of the question, if, in main.rs
, the function was used math::add
several times, it would be repetitive to have to type math::add
each time. In that case, one could do:
mod math; // Define o módulo `math` com os membros de `math.rs`.
// Elevo o "escopo" de `add`. Note que estou, essencialmente,
// encurtando o caminho até o membro (no caso, função) `add`:
use math::add;
// Agora posso chamar como:
math::add(1, 2); // Válido, caminho completo. OU:
add(1, 2); // Também válido (caminho encurtado definido pelo `use`).
Notice that in doing use math::add
, shorten the path to access the function add
. Now, no more need to prefix with math::
. Only add
that’s enough.
In relation to std::fs::read_to_string
, usually the programmer does this:
use std::fs;
// Pode utilizar como:
std::fs::read_to_string("./Cargo.toml");
fs::read_to_string("./Cargo.toml"); // Faz uso do encurtamento criado pelo `use` acima.
But it could also be:
use std::fs::read_to_string;
// Pode utilizar como:
std::fs::read_to_string("./Cargo.toml");
read_to_string("./Cargo.toml"); // Faz uso do encurtamento criado pelo `use` acima.
So the use
(more details here) can be used as a means to shorten module paths. In short, with or without the use
, we would still be able to access the function read_to_string
. The difference is that the use
allows us to shorten this path. It is extremely useful when we use the same path several times and if we want to avoid repetitions.
Cannot be used use
on some name that does not exist in the current scope.
That’s why it gave error (as shown in the question) to do this:
use foo;
What is foo
?
A module is required foo
defined in the scope to shorten the path to one of its members.
Lacked a definition mod foo
before the use foo
. Or a Crate foo
defined as project dependency.
Crates has its highest name set for all modules in the project. That’s why you can use it, for example, use std::fs
without making a mod std
before. The std
is a standard Crate of Rust. All Crates you define as project dependency are also exposed to your modules.
Summary of the opera
What brings a new name to the scope is the mod
, and not use
. The use
it doesn’t matter at all.
You need to define, with the directive mod
, the modules you will use. Crates, as the std
Rust or those you define as project dependency, are set automatically.
The use
is used to abbreviate a path that leads to a member of some module.
No, you don’t understand,
use
it looks likeimport
in Python, but not exactly the same.mod
has no Python equivalent because the mechanism looks but is not equal.– Maniero