Bringing Paths into Scope with the use
Keyword
The use
keyword creates shortcuts to paths, reducing repetition. Think of it as creating local aliases, similar to import statements in JavaScript/TypeScript.
mod front_of_house {
pub mod hosting {
pub fn add_to_waitlist() {}
}
}
use crate::front_of_house::hosting;
pub fn eat_at_restaurant() {
hosting::add_to_waitlist();
}
The use
statement creates a shortcut valid only within its scope:
mod front_of_house {
pub mod hosting {
pub fn add_to_waitlist() {}
}
}
use crate::front_of_house::hosting;
mod customer {
pub fn eat_at_restaurant() {
hosting::add_to_waitlist();
}
}
Idiomatic use
Patterns
Functions: Import the parent module, not the function directly
// Idiomatic
use crate::front_of_house::hosting;
hosting::add_to_waitlist();
// Less clear where function is defined
use crate::front_of_house::hosting::add_to_waitlist;
add_to_waitlist();
Structs/Enums/Types: Import the full path
use std::collections::HashMap; fn main() { let mut map = HashMap::new(); map.insert(1, 2); }
Name conflicts: Use parent modules to disambiguate
use std::fmt;
use std::io;
fn function1() -> fmt::Result {
// --snip--
Ok(())
}
fn function2() -> io::Result<()> {
// --snip--
Ok(())
}
Providing New Names with the as
Keyword
Create aliases to resolve naming conflicts:
use std::fmt::Result;
use std::io::Result as IoResult;
fn function1() -> Result {
// --snip--
Ok(())
}
fn function2() -> IoResult<()> {
// --snip--
Ok(())
}
Re-exporting Names with pub use
Make imported items available to external code (similar to TypeScript’s export { ... } from ...
):
mod front_of_house {
pub mod hosting {
pub fn add_to_waitlist() {}
}
}
pub use crate::front_of_house::hosting;
pub fn eat_at_restaurant() {
hosting::add_to_waitlist();
}
Re-exporting allows exposing a different public API structure than your internal organization.
Using External Packages
Add dependencies to Cargo.toml
:
rand = "0.8.5"
Then import and use:
use std::io;
use rand::Rng;
fn main() {
println!("Guess the number!");
let secret_number = rand::thread_rng().gen_range(1..=100);
println!("The secret number is: {secret_number}");
println!("Please input your guess.");
let mut guess = String::new();
io::stdin()
.read_line(&mut guess)
.expect("Failed to read line");
println!("You guessed: {guess}");
}
Standard library (std
) is available automatically but still requires explicit use
statements.
Nested Paths
Combine multiple imports from the same crate/module:
use rand::Rng;
// --snip--
use std::{cmp::Ordering, io};
// --snip--
fn main() {
println!("Guess the number!");
let secret_number = rand::thread_rng().gen_range(1..=100);
println!("The secret number is: {secret_number}");
println!("Please input your guess.");
let mut guess = String::new();
io::stdin()
.read_line(&mut guess)
.expect("Failed to read line");
let guess: u32 = guess.trim().parse().expect("Please type a number!");
println!("You guessed: {guess}");
match guess.cmp(&secret_number) {
Ordering::Less => println!("Too small!"),
Ordering::Greater => println!("Too big!"),
Ordering::Equal => println!("You win!"),
}
}
Use self
to import both the parent and child:
use std::io::{self, Write};
The Glob Operator
Import all public items (use sparingly):
use std::collections::*;
Commonly used in test modules and when implementing prelude patterns. Can make code less clear and cause naming conflicts.