use Keyword
The use keyword brings a path into the current scope.
Instead of writing long paths like:
crate::math::operations::add
everywhere, you can write:
use crate::math::operations::add;
and then just call:
add(2, 3);
use does not create or move code.
It only creates a shortcut (alias) to an existing item.
Where use Fits in Project Structure
Recall the hierarchy:
Crate
└── Modules
└── Items (functions, structs, enums, traits)
use works at any level to:
- import items from modules
- import items from other crates
- improve readability and API design
Basic Example: Without vs With use
Project structure
src/
├── main.rs
└── math.rs
math.rs
pub fn add(a: i32, b: i32) -> i32 {
a + b
}
Without use
mod math;
fn main() {
println!("{}", math::add(2, 3));
}
With use
mod math;
use math::add;
fn main() {
println!("{}", add(2, 3));
}
use math::add;bringsaddinto scope- Cleaner and easier to read
Importing from Nested Modules
Structure
src/
├── main.rs
└── math/
├── mod.rs
└── operations.rs
math/mod.rs
pub mod operations;
math/operations.rs
pub fn add(a: i32, b: i32) -> i32 {
a + b
}
main.rs
mod math;
use math::operations::add;
fn main() {
println!("{}", add(5, 3));
}
use with External Crates
Cargo.toml
[dependencies]
rand = "0.8"
Importing
use rand::Rng;
fn main() {
let n = rand::thread_rng().gen_range(1..=10);
println!("{}", n);
}
randis an external crateuse rand::Rng;imports a trait- Required so
.gen_range()works
use and Visibility Rules
use does not bypass privacy.
mod secret {
fn hidden() {}
}
use secret::hidden; // ❌ error: private function
To fix:
mod secret {
pub fn hidden() {}
}
use secret::hidden; // ✅
use with crate, self, and super
crate:: – from crate root
use crate::math::add;
self:: – current module
use self::helpers::log;
super:: – parent module
use super::config::Settings;
Grouped Imports (Clean & Idiomatic)
Without grouping
use std::fs::File;
use std::io::Read;
use std::io::Write;
With grouping
use std::io::{Read, Write};
use std::fs::File;
Glob Imports (*) – Use Carefully
use std::collections::*;
Pros
- Less typing
- Useful in tests or small modules
Cons
- Can cause name conflicts
- Reduces readability
Best practice: Avoid in public APIs.
Aliasing with as
Use aliases when names collide or are too long.
use std::io::Result as IoResult;
fn read_file() -> IoResult<()> {
Ok(())
}
Another example (name conflict)
use std::fmt::Result;
use std::io::Result as IoResult;
Re-exporting with pub use
This is very important for library design.
Example: Re-exporting API
src/
├── lib.rs
└── internal.rs
internal.rs
pub struct User {
pub name: String,
}
lib.rs
mod internal;
pub use internal::User;
Usage
use my_lib::User;
Why this matters
- Hides internal module structure
- Creates a clean public API
- Common in professional Rust libraries
use Scope Rules
A use statement applies:
- only to the module it is written in
- not automatically to submodules
mod a {
use crate::utils::log;
}
mod b {
// log is NOT available here
}
Idiomatic Placement of use
Rust convention:
use std::fs::File;
use std::io::{Read, Write};
fn main() {
// logic here
}
- Place
usestatements at the top of the module - After
moddeclarations - Before code
use vs mod (Common Confusion)
| Keyword | Purpose |
|---|---|
mod | Defines or loads a module |
use | Imports items into scope |
mod math; // declares module
use math::add; // imports function
Real-World Example (Binary + Library)
Structure
src/
├── main.rs
├── lib.rs
└── auth/
├── mod.rs
└── login.rs
lib.rs
pub mod auth;
auth/login.rs
pub fn login() {
println!("Login successful");
}
main.rs
use my_app::auth::login::login;
fn main() {
login();
}