Rust with diagrams: Ownership 2 - Data interacting with Move
Before delve deeper into how data interacts in memory, you should know about Rust's memory apporach.
When we are writing code that assigns data into Heap, we have two ways to handle variables and data interaction in memory: with Move and with Clone.
Variables & Data interacting with Move
Variables and data interaction with move means that data stored at the pointer address will be invalidated each time that is assigned to another variable. Therefore, if you want to use previous variables (which have been invalidated), Rust's compiler will throw an error. Let's to see an example:
let s1 = String::from("hello"); // 1. Assign "hello" into the Heap
let s2 = s1; // 2. Assign s1 to s2 invalidating s1
println!("{}, world!", s1); // 3. Rust throws an error because it can't read invalidated vairable
Let's see what's happening under the hood:
1. Assign "hello" into the Heap
"s1" group (ptr, len, capacity) is stored in the Stack where:
"ptr" is the pointer address where data "hello" is stored in the Heap (as shown in the right table).
"len" is how much memory (in bytes) are currently using.
"capacity" indicates the total amount of memory (in bytes) that the Stack group "s1" (shown in the table above) is received from the allocator.
2. Assign s1 to s2 invalidating s1
Stack data (s1) is copied (pointer, length and capacity), while Heap data is reassigned, not copied.
Rust calls the drop function to clean up the previous Stack data (s1), invalidating it.
This process is similar to a "shallow copy" but Rust also invalidates the original value.
3. Rust throws an error because it can read invalidated data
In the point 2, we discussing how Rust cleans up "s1" from the Stack, which means that it no longer exists and Rust cannot access it. Rust will provide an error if you are attempt to access an invalidated variable. Let's display the error:
cargo run
Compiling ownership v0.1.0 (file:///projects/ownership)
error[E0382]: borrow of moved value: `s1`
--> src/main.rs:5:28
|
2 | let s1 = String::from("hello");
| -- move occurs because `s1` has type `String`, which does not implement the `Copy` trait
3 | let s2 = s1;
| -- value moved here
4 |
5 | println!("{}, world!", s1);
| ^^ value borrowed here after move
|
= note: this error originates in the macro `$crate::format_args_nl` which comes from the expansion of the macro `println` (in Nightly builds, run with -Z macro-backtrace for more info)
help: consider cloning the value if the performance cost is acceptable
|
3 | let s2 = s1.clone();
| ++++++++
As you can see, the error message is very clear. It points out that "s1" is "value borrowed here after move" and suggests considering using clone to fix this error.
Next article
Once we see how variables & data interacting with move, i will summarize how variables & data interacting with clone.
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:
Subscribe to my newsletter
Read articles from Diego Barranco directly inside your inbox. Subscribe to the newsletter, and don't miss out.
Written by