Scopes, the areas of a program in which given variables are valid for access, are an absolutely vital component of Rust's guarantees of memory safety.
Separately from functions, scopes can be explicitly defined in Rust code with curly brackets:
fn main() {
let n: i32 = 10;
{
let n: i32 = 10 * 20;
println!("The scoped value of n is {}", n);
}
println!("The unscoped value of n is {}", n);
}
The above example is an instance of shadowing: the variable n is defined once in the main scope of the main function, then a new variable n is defined in the inner scope with a different value.
These two variables are entirely separate from one another, and they're only allowed to coexist in this piece of code because of the scope that separates them.
Once the inner scope finishes execution, the variable defined inside it is completely dropped, meaning that when the original variable n is printed, it has the value assigned to it independently of the inner scope.
Rust enforces the Resource Acquisition Is Initialisation (RAII) technique automatically during execution. This is an execution model commonly used in C++ programs that ties the window of access to a variable to the period of time between the creation of the variable, and the point at which the variable goes out of scope.
Rust has a built-in trait (a set of rules that modify the behaviour of a given data type, explained in more detail later) called Drop. This trait implements a function, drop(), on all data types, and the Rust runtime uses this function to delete out-of-scope variables from memory, no matter their data type.
It is completely forbidden to manually call the drop() function on any value whatsoever:
struct ToDrop {
i: i32
}
/// This impl tries to manually implement custom destruction
/// behaviour for ToDrop struct
impl Drop for ToDrop {
fn drop(&mut self) {
// some code to execute when struct is dropped
}
}
fn main() {
let i = ToDrop { i: 20 };
i.drop();
}
error[E0040]: explicit use of destructor method
--> src/main.rs:15:7
|
15 | i.drop();
| ^^^^ explicit destructor calls not allowed
|
help: consider using `drop` function
|
15 | drop(i);
| +++++ ~
For more information about this error, try `rustc --explain E0040`.
error: could not compile `temp` (bin "temp") due to 1 previous error
The second drop() function being suggested in the error output for the above code example is a different function entirely, and is part of std::mem, the built in memory management module for Rust. The functions in this module require considerably advanced knowledge of low-level Rust, and as such will not be explained further in this course.
Exercise:
Try adding a scope of your own to the function below, before the println!(), with a variable that shadows the existing variable: