Monday, May 1, 2023

Rust Ownership

 


In this post we will review the "ownership" in Rust.


Rust should be as fast as C/C++. This means it must not use garbage collector to manage the memory, but it want to avoid the while memory allocation/free hell. To bypass this, Rust uses ownership. Ownership means that only one variable owns the allocated memory, and the allocated memory is automatically freed by Rust upon exit from the variable scope.


fn play() {
let s1 = String::from("Hello World!");
println!("{s1}")
// s1 is freed upon end of the scope
}


But, this means you cannot have 2 owners of the same variable.

fn play() {
let s1 = String::from("Hello World!");

// move ownership to s2
let s2 = s1;
println!("{s2}");

// compile error - s1 "borrowed after move"
println!("{s1}");
}


To fix that we can use clone():

fn main() {
play()
}

fn play() {
let s1 = String::from("Hello World!");

let s2 = s1.clone();
println!("{s2}");

println!("{s1}");
}



Notice that this is also relevant for functions - once we send a variable to a function, the ownership moves to the function, and we no longer can use it.

fn play() {
let s1 = String::from("Hello World!");

// move ownership to play_too
play_too(s1);

// compile error - s1 "borrowed after move"
println!("{s1}");
}

fn play_too(text: String) {
println!("{text}");
}


We can use the clone() as before, but we can also send the variable by reference. This means we still own the variable, but the function can still use it. The variable will be freed upon the original scope end.

fn play() {
let s1 = String::from("Hello World!");

// send by reference
play_too(&s1);

println!("{s1}");
}

fn play_too(text: &String) {
println!("{text}");
}


Notice that we can also send it as mutable variable, but we must explicitly specify it when calling the function.

fn play() {
let mut s1 = String::from("Hello World!");

// send by reference
play_too(&mut s1);

println!("{s1}");
}

fn play_too(text: &mut String) {
text.push_str(" And Goodbye...");
println!("{text}");
}


Notice that Rust blocks dangling pointers, so in case the variable is freed, we cannot return a pointer to it:

fn play() -> &String {
let s = String::from("Hello World!");
// compile error: no value for it to be borrowed from
return &s;
}



No comments:

Post a Comment