Writing Idiomatic Rust
In this page:
Prefer Iterators Over Manual Loops
Idiomatic Rust often expresses transformations with iterator adapters like .map() and .filter() rather than manually written loops with mutable accumulator variables, since it is more declarative and less error-prone.
Example: Prefer Iterators Over Manual Loops
fn main() {
let numbers = vec![1, 2, 3, 4, 5];
let sum_of_squares: i32 = numbers.iter().map(|n| n * n).sum();
println!("{}", sum_of_squares);
}
Login to try C/C++/Java/PHP code in the editor
Borrow Instead of Clone When Possible
Reaching for .clone() to sidestep a borrow-checker complaint is usually a sign the code could be restructured to borrow instead, avoiding unnecessary memory allocation and copying.
Example: Borrow Instead of Clone When Possible
fn print_length(s: &str) {
println!("Length: {}", s.len());
}
fn main() {
let text = String::from("idiomatic");
print_length(&text);
println!("Still usable: {}", text);
}
Login to try C/C++/Java/PHP code in the editor
Use the Type System to Prevent Bugs
Idiomatic Rust leans on Option, Result, and enums to make invalid states impossible to represent, catching whole categories of bugs at compile time rather than with runtime checks.
Example: Use the Type System to Prevent Bugs
enum PaymentStatus {
Pending,
Completed(f64),
Failed(String),
}
fn describe(status: PaymentStatus) -> String {
match status {
PaymentStatus::Pending => String::from("still pending"),
PaymentStatus::Completed(amount) => format!("completed for ${}", amount),
PaymentStatus::Failed(reason) => format!("failed: {}", reason),
}
}
fn main() {
println!("{}", describe(PaymentStatus::Completed(49.99)));
}
Login to try C/C++/Java/PHP code in the editor
Listen to the Compiler
The Rust compiler's warnings, like an unused mut or an unused variable, are usually pointing at a genuine simplification opportunity, and idiomatic code takes them seriously rather than suppressing them.
Example: Listen to the Compiler
fn main() {
let value = 100; // no mut needed since it is never reassigned
println!("Clean, warning-free code: {}", value);
}
Login to try C/C++/Java/PHP code in the editor
- Overusing
.clone()everywhere to avoid dealing with the borrow checker, instead of restructuring code to borrow properly. - Writing verbose manual loops for tasks that idiomatic Rust would express with iterator adapters like
.map()/.filter(). - Ignoring compiler warnings (like unused
mutor dead code) instead of treating them as helpful hints toward cleaner code.
- Idiomatic Rust favors iterator adapters over manual loops when they express the same logic more clearly.
- Preferring borrowing over cloning avoids unnecessary allocations and keeps code closer to Rust's ownership philosophy.
- Leveraging the type system (like
Option/Result) to make invalid states unrepresentable is a hallmark of good Rust code. - Paying attention to compiler warnings often reveals opportunities to simplify or correct code.
Chapter Quiz — Complete all 8 topics to unlock
0/8 topics done
Complete these topics first: