Ownership is Rust’s unique feature and enable Rust to make memory safety guarantees without needing a garbage collector. It is a set of rules that govern how a Rust program manages memory. Thus in Rust, memory is managed through a system of ownership that the compiler checks. If any of the rules are violated, the program won’t compile.
For Rust, the memory is automatically returned once the variable that owns it goes out of scope. This is done by Rust calling drop
every time when a variable goes out of scope. (RAII)
For basic types(that does not involve heap allocation), a copy of x will be made and bind to y on the following code
let x = 5;
let y = x;
For data with heap allocation involved(i.e. String
), s2 will actually be pointing to s1’s content instead of making a copy. We can understand as that both s1 and s2 are pointing to the same string “hello” on the heap
let s1 = String::from("hello");
let s2 = s1;
println!("{}, world!", s1); // compiler error! s1 is moved
To ensure memory safety, after let s2 = s1;
, Rust considers s1
no longer valid. In other words, s1 is “moved” to s2. Rust will never automatically create deep copies of the data.
If we do want to deeply copy the heap data, we can specify it with clone
let s1 = String::from("hello");
let s2 = s1.clone();
println!("s1 = {}, s2 = {}", s1, s2);
and this will work just fine.
For primitive types like int, char, Rust has a special annotation called the Copy
trait that we can place on types that are stored on the stack. If a type implements the Copy
trait, variables that use it do not move, but rather are trivially copied, making them, still valid after assignment to another variable. But keep in mind that Rust won’t let us annotate a type with Copy
if the type, or any of its parts, has implemented the Drop
trait
The mechanics of passing a value to a function are similar to those when assigning a value to a variable. Passing a variable to a function will move or copy just as assignment.