DEV Community

Cover image for Variables and Primitive Data Types in Rust
Pedro Aravena for Vaultree

Posted on


Variables and Primitive Data Types in Rust

In our last article, we learned how to start a project in Rust. This time we'll share tips on what you need to know about variables and their types. We'll learn how to create and use them, and discuss mutability and immutability, constants, and shadowing.

Image description

Variables, Mutability, and Immutability

Variables are spaces in computer memory used to store certain data. We can think of them as if they were "boxes" to store some item.

In Rust, when we declare a variable we use the reserved word "let". Check it out:

let x = 10;

let y: f64;
y = 17;
Enter fullscreen mode Exit fullscreen mode

let x = 10; -> where "x" is the name of the variable and "= 10" assigns the value 10 to "x". Rust is a statically typed language, that is, every variable created must have a type. In this line we are not adding a type because Rust can infer it according to the assigned data - as in approximately 99% of the cases. However, you'll find cases where Rust does not infer the type.

let y: f64; y = 17; -> We can declare first and initialise later, but it's very unusual to use it that way. If the variable is declared and not initialised and we try to use it, we will have a compilation error, because Rust does not allow a variable to not have a value.
As a convention, variable names that have compound names will be written in snake_case, such as explicit_type.
By default, Rust uses immutable variables, which means that it is impossible to change their value after initialization. This is a way to keep your code secure.

In the case below, an error would be displayed:

let x = 10;
x = 17;
Enter fullscreen mode Exit fullscreen mode

However, we have the option of making a variable mutable, for that we will add the "mut" keyword, as follows:

let mut x = 10;
x = 17;
Enter fullscreen mode Exit fullscreen mode

In this way, we can make changes to this variable.
To print the value of a given variable, do as follows:

println!("The value of x is {}", x);

The "{}" is a placeholder that we replace with the value of the variable that comes after the comma.


In addition to variables we can create constants. Constants will always be immutable, and to create constants we use the keyword "const" instead of "let", and the type needs to be specified.
Another difference with constants is that they can be declared in any scope, including the global scope. They cannot be the results of functions or some value that could only be calculated at runtime.

Let's see an example:

const PI: f64 = 3.14;


In Rust, it is possible to declare a new variable using the same name that was already used before, and this new one overshadows the previous variable, being able to change even its type. Let's create a project to exemplify, enter the directory and run VS Code:

cargo new variables
cd variables
code .
Enter fullscreen mode Exit fullscreen mode

In the file we will replace the existing content with:

const PI: f64 = 3.14159;

fn  main() {
    let  mut x = 10;
    println!("The value of x is {}", x);

    x = 17;
    println!("The value of x is {}", x);

    let x = "test";
    println!("The value of x is {}", x);

    println!("The value of PI const is {}", PI);
Enter fullscreen mode Exit fullscreen mode

As we can see, we created a variable called x and assigned the value 10 to it, which means that it is of type i32. It was created with the word mut, meaning it is mutable, so we could change the value of this variable by assigning the value 17 to it. Below we declare a variable with the same name, but we add a text to it, which means that the value has been changed and the type as well. We could have used shadowing even if it wasn't mutable.

Let's run this project with the command: cargo run. The output will be similar to:

Compiling variables v0.1.0 (/home/desktop/dev/workspace/rust)
Finished dev [unoptimized + debuginfo] target(s) in 0.25s
Running `target/debug/variables`
The value of x is 10
The value of x is 17
The value of x is test
The value of PI const is 3.14159
Enter fullscreen mode Exit fullscreen mode

As we can see, Rust has good mechanisms to avoid errors that are very common in most languages, forcing the initialization of the variable it does not allow, for example, a Null Pointer so well known in languages like Java, C#, etc. It's one of the reasons why so many people claim it to be their favourite language.

Moving on, let's talk about how primitive data types work in Rust.

Image description

Primitive Data Types

Rust has a list of data types that are considered primitive. Rust primitive types can be grouped into scalar and composite data types.
What are primitive data types?
Primitive data types, as the name implies, come with a programming language. They are built-in and, when combined, can form more complex data types, called non-primitive data types.
As we mentioned, the Rust programming language comes with a list of built-in primitive data types that developers can use as building blocks for other data types.

Primitive data types in Rust

We want to group them first into scalar and composite data types. The difference between these two is that composite types contain multiple values ​​in one type whereas scalar types only contain one value.

Primitive Scalar Types in Rust

There are four scalar primitive types that you should be familiar with in Rust:

Boolean data type

The Boolean data type is said to be true or false, like this:

let active = true;
let inactive = false;
Enter fullscreen mode Exit fullscreen mode

Boolean data types are primarily used for comparing values or logic — for example, to check whether a test score is A, B, or C.

Char data type

The character type is a 4-byte data type. It is used to store single characters like:

let first = 'a';
let second = 'b';
let symbol = '∞';
Enter fullscreen mode Exit fullscreen mode

Character data types are used to store single characters, allowing the memory allocation in Rust to remain small.

Integer data type

There are several types of integer data, which fall into two categories: signed (i) and unsigned (u). They include the following: i8, i16, i32, i64, isize, u8, u16, u32, u64, usize. here are some examples:

let height = 189; //u8
let weight = 78; // u8
let size = 54; // u8
let data = -455// i8
Enter fullscreen mode Exit fullscreen mode

Floating data type

Floating data types are always f32or f64, which can vary widely from negative to positive numbers:

f32 ---> -3.8x10^8 to +3.8x10^8
f64 ---> -1.8x10^308 to +1.8x10^308
Enter fullscreen mode Exit fullscreen mode

Floats are what we call decimals. See some examples below:

let interest = 1.20;
let returns = 2.80;
let agency = 10.0;
Enter fullscreen mode Exit fullscreen mode

Composite Primitive Types in Rust

Array data type

An array is a data type that contains a group of elements. Its size is always fixed and of the same data type, like this:

let counts: [i32; 7] = [4, 2, 4, 8, 3, 2, 4, 8];
let grade: [i32; 4] = [20, 40, 34, 70];

In the examples above, the array contains 7 elements of the i32(integer) data type, while the array grade contains 4 elements of the i32 data type.

String data type

There are two string data types in Rust: String(String Object) and &str(String literal).
The String object is not in the main language but is provided in the standard library. It is also the most common string type because it is mutable. To create a String:


let name = String::new();
name.push_str = 'Pedro Aravena';
println("{}", name);
Enter fullscreen mode Exit fullscreen mode

The &str data type in Rust is considered a slice of string and is said to be immutable, meaning that it cannot be changed during the lifetime of the program. Take a look at the example below:

let name:&str = 'Pedro Aravena';
let company:&str = 'Vaultree';
Enter fullscreen mode Exit fullscreen mode

In the example above, for the lifetime of this program, the name will always be associated with the string Pedro Aravena, while the company will always be associated with the string Vaultree.

Slice data type

Slices are similar to matrices, but there are some differences. While array sizes are fixed, slices are dynamic in size; the length is not known at compile time and the data is split into a new collection.

Let's see the example below:

let grades: [132:6] = [20, 10, 30, 40, 50, 10, 20];
let slice = &[20...4]; // 20, 10, 30, 40
Enter fullscreen mode Exit fullscreen mode

Slices are also a pointer to the above string object where we can retrieve a given character in the string value. We can also borrow elements from a slice to use elsewhere.

Tuple data type

In other languages like JavaScript, tuples are called objects. They are fixed data types that contain different types of elements — unlike arrays, which can only contain the same type of elements.

let employee: (&str, i32, &str) = ('Pedro Aravena', 25, 'Developer Advocate');
Enter fullscreen mode Exit fullscreen mode

In the example above, the employee tuple contains three elements: a string (Pedro Aravena), an integer (25), and another string (Developer Advocate).


Understanding how to work with all the different types of primitive data in Rust is extremely helpful. We're here to support your Rust journey. If you have any questions, please drop them below and stay tuned for upcoming articles on functions and flow controls.

For more content like this, join the Vaultree Community.
Image description


About Vaultree

Vaultree’s Encryption-in-use enables businesses of all sizes to process (search and compute) fully end-to-end encrypted data without the need to decrypt. Easy to use and integrate, Vaultree delivers peak performance without compromising security, neutralising the weak spots of traditional encryption or other Privacy Enhancing Technology (PET) based solutions. Follow Vaultree on Twitter (@Vaultree), LinkedIn, Reddit (r/Vaultree) or Visit, and sign up for a product demo and our newsletter to stay up to date on product development and company news.

Latest comments (0)

12 APIs That You Will Love

Free and easy to use APIs for your next project, learning a new technology, or building a new feature.