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,
useit looks likeimportin Python, but not exactly the same.modhas no Python equivalent because the mechanism looks but is not equal.– Maniero