Rust with diagrams: Ownership 5 - Return Values & Scope
Rust documentation with diagrams to fast learn and remember. Let's learn together in Chapter 4.1.
Until now, we discussing about Rust memory approach and how variables & data interacting on Stack & Heap. It's time to learn about Ownership Rust concept.
What is Ownership?
Ownership is a set of rules that govern a Rust program manages memory. All programs have to manage the way they use a computers memory while running. Other languages have garbage collector that regularly looks for no-longer-used memory as the program runs. In Rust, memory is managed through a system of ownership with a set of rules that the compiler checks.
Ownership rules
Each value in Rust has an Owner.
There can only be one owner at a time.
When the owner goes out of scope, the value will dropped.
What is the variable scope?
Variable scope refers to the portion of the code where a variable is accessible and can be used.
The variable is valid from the point at which it's declared the end of the current scope.
Let's see an example:
{ // s is not valid here, it’s not yet declared
let s = "hello"; // s is valid from this point forward
// do stuff with s
} // this scope is now over, and s is no longer valid
Ownership & Functions
If you recall the second Ownership rule mentioned in this article: "There can only be one owner at a time". This mean that Ownership will be moved and returned (if needed) by functions.
To better understand how ownership works in functions, let's examine a code example that implements the concepts discussed in all the "Ownership" articles written before, including data interaction with Heap & Stack and scope.
Let's see it:
fn main() {
let s = String::from("hello"); // s comes into scope (assigned into Heap)
takes_ownership(s); // s's value moves into the function... (data interacting with move s is invalidated)
// ... and so is no longer valid here
let x = 5; // x comes into scope (assigned to Stack)
makes_copy(x); // x would move into the function,
// but i32 is Copy, so it's okay to still
// use x afterward
} // Here, x goes out of scope, then s (last in, fist out). But because s's value was moved, nothing
// special happens.
fn takes_ownership(some_string: String) { // some_string comes into scope
println!("{}", some_string);
} // Here, some_string goes out of scope and `drop` is called. The backing
// memory is freed.
fn makes_copy(some_integer: i32) { // some_integer comes into scope
println!("{}", some_integer);
} // Here, some_integer goes out of scope. Nothing special happens.
Return Values & Scope
Let's examine more examples to understand scope returns:
fn main() {
let s1 = gives_ownership(); // gives_ownership moves its return
// value into s1
let s2 = String::from("hello"); // s2 comes into scope
let s3 = takes_and_gives_back(s2); // s2 is moved into
// takes_and_gives_back, which also
// moves its return value into s3
} // Here, s3 goes out of scope and is dropped. s2 was moved, so nothing
// happens. s1 goes out of scope and is dropped.
fn gives_ownership() -> String { // gives_ownership will move its
// return value into the function
// that calls it
let some_string = String::from("yours"); // some_string comes into scope
some_string // some_string is returned and
// moves out to the calling
// function
}
// This function takes a String and returns one
fn takes_and_gives_back(a_string: String) -> String { // a_string comes into
// scope
a_string // a_string is returned and moves out to the calling function
}
Is good to know that Rust does let us return multiple values using a tuple, let's see an example:
fn main() {
let s1 = String::from("hello");
let (s2, len) = calculate_length(s1);
println!("The length of '{}' is {}.", s2, len);
}
fn calculate_length(s: String) -> (String, usize) {
let length = s.len(); // len() returns the length of a String
(s, length)
}
Conclusion
Keep in mind how ownership is moved or returned to handle it correctly assumes a lot work for a concept that should be common. That's why Rust has a feature for using a value without transferring ownership, called references.
Next article
Once here, we can check 4.1 Chapter how learned. In next article i will summarize references and borrowing concept.
I wish that this content helps you to learn Rust while i do it. If you have doubts, suggestions or you see errors, please don't be shy and comment on them. The goal of this content is learn together!
References: