Rust — Scope
Braces create scopes
fn main() {
let outer = "visible everywhere in main";
{
let inner = "only inside this block";
println!("{} / {}", outer, inner); // both readable ✓
}
// println!("{}", inner) ❌ inner dropped at its closing brace
}
Variables exist from declaration to the end of their enclosing block. Lookup walks outward through nested blocks.
Scope end = memory freed (ownership preview)
The moment a variable leaves scope, Rust calls drop and frees it:
{
let s = String::from("heap data"); // allocates
println!("{}", s);
} // ← s dropped, memory returned
No garbage collector sweeps later. Deterministic cleanup at brace-close is ownership's most visible effect — and why Rust code often looks like "the compiler wrote my destructors."
Shadowing revisited — scoped rebinding
let x = 5;
{
let x = x * 2; // shadows INSIDE this block only
println!("{}", x); // 10
}
println!("{}", x); // 5 — original untouched
Each block can reuse names safely; outermost bindings survive.
Early returns & scope
Values created inside a function vanish on return:
fn make_greeting() -> String {
let name = String::from("Ada");
format!("Hello, {}", name) // moved out to the caller ✓
}
// 'name' is gone here, but its content escaped via the return
Returning moves ownership outward — the data survives because someone else now owns it.
Temporary scopes for borrowing peace
Later lessons show borrow-checker conflicts; a common fix is shrinking scope so borrows end sooner:
let mut scores = vec![90, 85];
{
let first = &scores[0]; // borrow confined to this block
println!("{}", first);
} // borrow ends here
scores.push(95); // ✓ no conflict anymore
Idiom: wrap short borrows in bare { } blocks when the borrow checker complains.
No null — Option instead
Scope rules pair with Rust's absence of null: an uninitialized variable cannot be read, and "maybe missing" values are explicit Option<T>:
let maybe: Option<i32> = Some(5);
match maybe {
Some(v) => println!("got {}", v),
None => println!("nothing"),
}
Uninitialized-use errors are compile errors; null-dereference crashes are structurally impossible. That's the safety story from lesson one, finally visible.
Mini Practice
- Three nested blocks reusing the same variable name; print each level.
- Prove drop timing with a struct implementing Drop printing a message.
- Return a String built locally; confirm caller owns it.
- Fix a borrow conflict by wrapping a read in a temporary block.
- Explain in one sentence why Rust needs no garbage collector.
Next: strings →
Related Topics
Frequently Asked Questions about Scope
What is Scope in Rust?
Scope is a fundamental concept in Rust. This lesson explains it step by step with clear examples, making it easy for beginners to understand.
How do I learn Scope?
Start by reading the explanation above, then try the code examples. Practice by modifying the examples and experimenting with different values. Hands-on practice is the best way to learn Scope.
Why is Scope important in Rust?
Scope is essential for Rust development. Understanding this concept will help you write better code and solve real-world problems more effectively.