Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Use of undeclared type or module `std` when used in a separate module

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")); } 
like image 982
luke Avatar asked May 02 '14 18:05

luke


2 Answers

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).

like image 60
Renato Zannon Avatar answered Sep 17 '22 21:09

Renato Zannon


Nowadays, std is directly accessible from everywhere, so the code you showed is compiling as you would expect.

Furthermore, extern crate is no longer needed in Rust edition 2018. Adding a dependency to Cargo.toml makes the crate name directly available as a top-level identifier.

like image 24
TheOperator Avatar answered Sep 18 '22 21:09

TheOperator