Rust 2
Rust 2
On Rust ownership
• In Rust, ownership is a system the compiler uses to ensure memory safety.
• It manages ownership by keeping track of which variables own which values, and making sure that those
values are only dropped when they are no longer being used.
• Rust guarantees memory safety with a feature called ownership.
• memory management is handled by the Rust compiler using the ownership model.
• A Rust compiler will automatically insert a drop statement to free the memory. It uses the ownership model
to decide where to free memory; when the owner goes out of scope, the memory is freed.
• When doing assignments (let x = y) or passing function arguments by value (foo(x)), the ownership of the
resources is transferred. In Rust-speak, this is known as a move.
let x =5;
}
What are the stack and the
heap?
• The stack and heap are both memory storage segments that are available for your code to use at runtime.
• Rust is a system programming language, how values are stored (in the stack or heap) is essential to how the language
behaves.
These books are arranged in a way that the last book is placed on top of the stack and the first book is at the bottom.
Ideally, we wouldn’t want to slide the bottom book out from under the stack, it would be easier to pick a book on top of
to read.
This is exactly how memory is stored in the stack it uses the last in, first out method.
it stores values in the order it gets them but removes them in the opposite order. It’s also important to note that all data
stored in the stack have a known size at compile time.
What are the stack and the
heap?
• Memory allocation in the heap:
Think of going to buy a shirt for a friend. You don’t know the exact size shirt your friend wears,
but seeing him frequently, you think he might be a medium or large. While you aren’t completely
sure, you buy the large because he will still be able to physically fit into it, even if he’s a medium.
This is how memory allocation in the heap works.
When you have a value (your friend) for which you don’t know the exact amount of memory it
will require (size of t-shirt), you request for a specific amount of space for the value. The
allocator finds a spot in the heap that is big enough and marks that spot as in use. This is an
important difference between the stack and the heap: we don’t need to know the exact size of
the value being stored in the heap.
• Allocating on the heap involves searching for an empty space big enough to
match the amount of memory you requested, and returning an address to the
location which will be stored in the stack. Retrieving a value from the heap
requires you to follow a pointer to the place where the value is stored in the
heap.
• Allocating on the heap looks like book indexing, where a pointer for a value
stored in the heap is stored in the stack. However, the allocator also needs to
search for an empty space that is big enough to contain the value.
• Local variables of a function are stored on the function stack, whereas data types,
such as String, Vector, Box, etc., are stored on the heap. It is important to
understand the memory management of Rust to ensure the app behaves as
intended.
Ownership rules
• Ownership has three basic rules that predict how memory is stored in the stack and in the heap:
Each value can only have one owner at a time .When the owner goes out of the scope, the value will be dropped:
fn main() {
{// scope begins
let s = String::from("hello"); // s comes into scope
}// the value of s is dropped at this point, it is out of scope
}
How ownership works
When the variable goes out of scope, the Rust ownership feature allows for the memory to be returned
(freed).
Clone and copy
// stack case
fn main() {
let a = "5";
let b = a; // copy the value a into b
println!("{}", a) // 5
println!("{}", b) // 5
}
//heap case
fn main() {
let a = String::from("hello");
let b = a; // copy the value a into b
println!("{}", a) // This will throw an error because a has been moved or ownership has been transferred
println!("{}", b) // hello
}
heap are stored like an indexing process, where the pointer is stored in the stack
• When you copy a value that is stored
on the heap, the system automatically
copies only the pointer, leaving out the
heap data. Since data can have one
owner, ownership of string is
transferred from a to b.
fn main() {
let a = String::from("hello");
let b = a.clone(); // creates a copy of
data on the heap and return pointer to it
Ownership is managed copying the value, so after assigning x to y you get two variables owning two values (value is 5in our
example).
Example ownership transfer
fn main() {
let x = 5;
let mut y = x;
y = 8;
// OUTPUT
x = 5, y = 5
x = 5, y = 8
Why ownership is so important?
• scope is an area of code where a variable “live”.
• A variable defined in a scope isn’t visible outer of that scope.
// stack variable scope example
fn main() {
let a = 3;
// nested scope
{
// Allocate an integer on the heap
let b = 5;
println!("Do something with {b}");
}
}
// Here 'a' doesn't exist anymore
Ownership with variables allocated in
the heap
fn main() {
let a = String::from("hello");
// nested scope
{
// Allocate an integer on the heap
let b = String::from("world");
println!("Do something with {b}");
}
} // Here, s3 goes out of scope and is dropped. s2 goes out of scope but was
// moved, so nothing happens. s1 goes out of scope and is dropped.
fn main() {
let s1 = String::from("hello");
// &str type
let a = &s[0..4]; // doesn't transfer ownership, but references/borrow the first four letters.
let b = &s[4..8]; // doesn't transfer ownership, but references/borrow the last four letters.
println!("{}", a); // prints Nige
println!("{}", b); // prints rian
let v=vec![1,2,3,4,5,6,7,8];
// &[T] type
let a = &v[0..4]; // doesn't transfer ownership, but references/borrow the first four element.
let b = &v[4..8]; // doesn't transfer ownership, but references/borrow the last four element.
println!("{:?}", a); // prints [1, 2, 3, 4]
println!("{:?}", b); // prints [5, 6, 7, 8]