
File as a module
Modules can also be created as files. For instance, for a main.rs file in a directory named foo, we can create a module bar as a file in the same directory as foo/bar.rs. Then in main.rs, we need to tell the compiler of this module, that is, declare the module with mod foo;. This is an extra step when using file-based modules. To demonstrate using a file as a module, we have created a directory named modules_demo, which has the following structure:
+ modules_demo
└── foo.rs
└── main.rs
Our foo.rs contains a struct Bar, with its impl block:
// modules_demo/foo.rs
pub struct Bar;
impl Bar {
pub fn init() {
println!("Bar type initialized");
}
}
We want to use this module in main.rs. Our main.rs, has the following code:
// modules_demo/main.rs
mod foo;
use crate::foo::Bar;
fn main() {
let _bar = Bar::init();
}
We declare our module, foo, using mod foo;. We then use the Bar struct from the module by writing use crate::foo::Bar. Notice the crate prefix in use crate::foo::Bar; here. There are three ways to use an item from a module depending on the prefix you use:
Absolute imports:
- crate: An absolute import prefix that refers to the the current crate's root. In the preceding code, this would be the root module, that is, main.rs file. Anything after the crate keyword is resolved from the root module.
Relative imports:
- self: A relative import prefix that refers to an item relative from the current module. This is used when any code wants to refer to its containing module, for example, use self::foo::Bar;. This is mostly used when re-exporting items from a child module to be available from the parent module.
- super: A relative import prefix that can use and import an item from the parent module. A child module such as the tests module would use this to import items from the parent module. For example, if a module bar wants to access an item Foo from its parent module foo, it would import it as use super::foo::Foo; in module bar.
The third way to create modules, is to organize them as directories.