I have the following code:
pub mod a {
#[test]
pub fn test() {
println!("{:?}", std::fs::remove_file("Somefilehere"));
}
}
I get errors when I compile this:
error[E0433]: failed to resolve. Use of undeclared type or module `std`
--> src/main.rs:4:24
|
4 | println!("{}", std::fs::remove_file("Somefilehere"));
| ^^^ Use of undeclared type or module `std`
However, removing the inner module and compiling the code it contains by itself works fine:
#[test]
pub fn test() {
println!("{:?}", std::fs::remove_file("Somefilehere"));
}
What am I missing here? I get the same errors if the module is in a separate file:
main.rs
pub mod a;
a.rs
#[test]
pub fn test() {
println!("{:?}", std::fs::remove_file("Somefilehere"));
}
By default, the compiler inserts extern crate std;
at the beginning of the crate root (the crate root is the file that you pass to rustc
). This statement has the effect of adding the name std
to the crate's root namespace and associating it with a module that contains the public contents of the std
crate.
However, in child modules, std
is not automatically added in the module's namespace. This is why the compiler cannot resolve std
(or anything that starts with std::
) in a module.
There are many ways to fix this. First, you can add use std;
in a module to make the name std
refer, within that module, to the root std
. Note that in use
statements, the path is treated as absolute (or "relative to the crate's root namespace"), whereas everywhere else, paths are treated as relative to the current namespace (be it a module, a function, etc.).
pub mod a {
use std;
#[test]
pub fn test() {
println!("{:?}", std::fs::remove_file("Somefilehere"));
}
}
You can also use a use
statement to import more specific items. For example, you can write use std::fs::remove_file;
. This lets you avoid having to type the whole path to remove_file
and just use the name remove_file
directly within that module:
pub mod a {
use std::fs::remove_file;
#[test]
pub fn test() {
println!("{:?}", remove_file("Somefilehere")));
}
}
Finally, you can avoid using use
altogether by prefixing the path with ::
to ask the compiler to resolve the path from the crate's root namespace (i.e. turning the path into an absolute path).
pub mod a {
#[test]
pub fn test() {
println!("{:?}", ::std::fs::remove_file("Somefilehere"));
}
}
The recommended practice is to import types (structs, enums, etc.) directly (e.g. use std::rc::Rc;
, then use the path Rc
), but to use functions through an import of their parent module (e.g. use std::io::fs;
, then use the path fs::remove_file
).
pub mod a {
use std::fs;
#[test]
pub fn test() {
println!("{:?}", fs::remove_file("Somefilehere"));
}
}
Side note: You can also write self::
at the beginning of a path to make it relative to the current module. This is more often used in use
statements, since other paths are already relative (though they are relative to the current namespace, whereas self::
is always relative to the containing module).