OneBite.Dev - Coding blog in a bite size

Variable Scope in Rust

Understand the variable scope in Rust. This is an important part so we can learn how Rust allocating their memory later

Understand the variable scope in Rust is important, so we can learn how Rust allocating their memory later

Each variable declared in Rust has their scope. Scope is where that variable is valid.

Normally, A variable’s scope is only valid on a function where they’re declared

fn main() {
    let s = "hallo"
  }
  //S scope only inside main function

Or if you declare a scope with curly brackets

fn main() {
    let x = "yo"
    {
	    let s = "hallo"
     }
     //S only valid inside above curly brackets
     .... //continue
  }

In Rust, the memory is automatically returned once the variable that owns it goes out of scope.

Rust will call a function called drop automatically at a closing curly bracket (you don’t need to deal with that). This drop function will free the memory for us.

Complex case

Assume we declared a variable based on other variable

fn main() {
    let x = 5;
    let y = x;
}

Since 5 is a primitive value and the size is already known, it’s very straightforward: Now y and x has value of 5. Y will just copy x value. The whole thing will be stored in a stack.

But let’s take a look at string version

fn main() {
    let s1 = String::from("hello");
    let s2 = s1;
}

With more complex variable like this, especially when the size is unknown, Rust will use both Heap and Stack.

Double free problem

Based on previous example

fn main() {
    let s1 = String::from("hello");
    let s2 = s1;
}

What happen when we declare s1:

Stack will store the pointer, length and capacity of the string, while Heap will store the value each of character ‘h’ ‘e’ ‘l’ ‘l’ ‘o’ with their index.

**What happen when we assign s2 = s1:
**The data of the Stack will be copied. But it will point to the same Heap. Since it’s expensive to copy the heap, imagine if it has a very large value.

So now.. there are 2 Heaps used but only one Stack.

*images from doc rust-lang.org

**What’s the problem?
**If one of the two variables s1 or s2, goes out of scope, the what happen? since both of them pointing to the same value.

Or other problem is “double free”. When both of variables goes out of scope, then they try to free same memory in heap. Such an error can potentially lead to security vulnerabilities.

How Rust deal with this

This is a very important point, when a value is copied, the original variable will be cleared by Rust. So..

fn main() {
    let s1 = String::from("hello");
    let s2 = s1;

    println!("{}, world!", s1);
}

Will return an error. Since s1 is not valid anymore!

So it’s safe to say, when we assign a variable to other variable: We are moving the first var to the second var.

How to copy the whole thing?

If you want to copy the whole variable, both in stack and heap. We can use clone

fn main() {
    let s1 = String::from("hello");
    let s2 = s1.clone();

    println!("s1 = {}, s2 = {}", s1, s2);
}

But take a note, this process is expensive.

If you use an integer or other simple data type, you don’t need to do a clone, since Rust will automatically call copy function to do that. Here is the list of data types that don’t need clone

← Looping in Rust...
What is ownership in Rust... →
rust