Learning Rust 🦀: 02- The basics: Variables and Data Types
Tags: learning, rust, programming, development
Published: 2023-06-06 06:04:54

In this article we will dig a little deeper into Rust. We will discuss the basic programming concepts but from Rust perspective. Here you will notice the similarities between Rust and the other languages but we won't delve too deep into Rust's unique traits.  

>#### ⚠️ Remember!
You can find all the code snippets for this series in its [accompanying repo](https://github.com/FadyGrAb/rust-learning-series)  
If you don't want to install Rust locally, you can play with all the code of this series in the official [Rust Playground](https://play.rust-lang.org/?version=stable&mode=debug&edition=2021) that can be found on its official page. (cargo commands won't run though. But you mostly won't be needing it)
⚠️⚠️ The articles in this series are loosely following the contents of "The Rust Programming Language, 2nd Edition" by Steve Klabnik and Carol Nichols in a way that reflects my understanding from a Python developer's perspective.

⭐ I try to publish a new article every week (maybe more if the Rust gods 🙌 are generous 😁) so stay tuned 😉. I'll be posting "new articles updates" on [my LinkedIn](https://www.linkedin.com/in/fady-abdelmassih).

## Table of contents
- [The "_main_" function](#the-main-function)
- [Variables](#variables)
- [Data Types](#data-types)
    - [Scaler Types](#scalar-data-types)
        - [Integer Types](#integer-types)
        - [Floating-Point Types](#floatingpoint-types)
        - [The Boolean Type](#the-boolean-type)
        - [The Character Type](#the-character-type)
    - [Compound Types](#compound-types)
        - [The Tuple Type](#the-tuple-type)
        - [The Array Type](#the-array-type) 

### The main function
We saw in the [last article](https://dev.to/fadygrab/learning-rust-1-intro-and-setup-5a77) that when we create a new project with `cargo`, a new file called `main.rs` is created for us in the `./src/` directory and in that file, we have the _"main"_ function:
```rust
fn main() {
    println!("Hello, world!");
}
```
The `main.rs` file and the `main` function act as the entry point to our program. Your program won't run unless it has those! As opposed to Python, in which you don't need to define a main function or file.  
As we can see, the _main_ function doesn't take any arguments initially and doesn't return anything (actually it returns a unit data type "()" but more on that later).

### Variables
Variables in Rust are defined by the `let` and `const` keywords (Yes! just like JavaScript 😉). They are _immutable_ by default (their values can't be changed once set). Let's test this, create a new project called "basics" in your current directory
```bash
cargo new basics
```
And replace the code in `main.rs` with the following and run it (remember to run a Rust code, type `cargo run`):
```rust
fn main(){
    let x = 5;  // Variables are immutable by default
    x = 6;      // Error: cannot assign twice to immutable variable `x`
}
```
This code will error out but I'd like to highlight a very beautiful thing about Rust, its Error display method for the errors stack. It is just amazing! Rust uses colors while displaying errors, shows you where and explains why the error occurred and often provides suggestions to help solve them!  

![Rust Error](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/5foc4j636te9nb2m3jc7.png)  
To fix this error, we will have to make our variable _x_ a "mutable variable" by using the `mut` keyword.
```rust
fn main() {
    // let x = 5;   // Variables are immutable by default
    // x = 6;       // Error: cannot assign twice to immutable variable `x`
    let mut x = 5;
    x = 6; // This won't error out as x is mutable now.
    println!("The value of x is {x}")
}
```
Here we initially set `x` to 5 and used the `mut` keyword to tell our program that this variable is _mutable_ then we changed its value to 6 and used the `println!` macro to print its value in stdout (Rust uses curly-braces "{}" for string interpolation in the println! macro). You should see the following printed on your screen (ignore any warnings that appears for now).
```bash
The value of x is 6
```

The `const` keyword is the other method to define variables in Rust except they are always immutable. Constants can be declared in the global scope and must be a known value/calculation at compile time (can't be calculated at runtime)
```rust
const MINUTES_IN_DAY: u32 = 1 * 24 * 60;      // Valid
const WORK_HOURS_PER_WEEK = user_input;  // Invalid
```
(u32 is the data type of the constant which stands for "unsigned" 32 bits integer)

### Data Types
Rust is a statically typed language, which means that it must know the types of all variables at compile time. The Rust compiler does a good job at inferring them. But when it can't, it's the programmer's job to declare the variables type. Take a look at this example:
```rust
let guess = "42".parse().expect("Not a number"); // Error: type annotations needed
```
This statement will fail despite that "42" is an integer! that's because Rust has several integer types the compiler needs to know which one you mean.
Broadly, Rust has two main categories for its data types:
- **Scalar**: Represents a single value.
- **Compound**: Represents a group of multiple values.

### Scalar Data Types
#### Integer Types
Like Python and the other languages, an integer is a whole number without a fractional component. In Rust, the integer type is written as follows:
> [i/u][size in bits]

Where "i" is a signed number (can hold negative values) and "u" is an unsigned number (only positive values). The size in bits can be 8, 16, 32, 64 and 128 which determines the maximum value that the variable can hold (Integer type defaults to i32). 
So, for example:
```
i8: 8-bit signed integer (from -128 to 127)
u8: 8-bit unsigned integer (from 0 to 255)
```
There are also the "isize" and "usize" types that depends on the machine architecture that the program runs on (either 32-bit or 64-bit).
Beware that if you use an integer type smaller that you have intended it to be, ***Integer Overflow*** may occur!

#### Floating-Point Types
Like integers, floating-point types are denoted with the letter "f" and they can be a single precision (f32) or a double precision (f64) (the default is f64) 

#### The Boolean Type
Boolean in Rust are either `true` or `false` and denoted by the `bool` keyword. Like in other languages, Boolean type is frequently used in condition checks.

#### The Character Type
In Rust, the Character type is defined by single quotes "''" and denoted by the `char` keyword. It holds single character (Unicode is valid)

### Compound Types
#### The Tuple Type
The tuple is Rust as a way to group several values together with different types into one compound type. It has a fixed size and can't grow or shrink. Like in Python, it's a comma-separated list of values
```rust
let ip_address: (u8, u8, u8, u8) = (168, 1, 1, 10);
let user: (&str, u8, char, bool) = ("Fady", 37, 'm', true);
```
To get the values for a Tuple, you can use pattern matching to "destruct" the tuple 
```rust
let (a, b, c, d) = ip_address;
println!("The IP address is {a}.{b}.{c}.{d}")
```
Or you can access the tuple elements by using a period (.) followed by the index of value (zero indexed)
```rust
println!("The IP address is {}.{}.{}.{}", ip_address.0, ip_address.1, ip_address.2, ip_address.3)
```
A Tuple without any values has a special name, *unit* (remember the return value of the main function?). It is written as () and represents an empty value or an empty return type (like void in C an Java).

#### The Array Type
Arrays are another way to group together multiple values in a compound type but this time all the values must be of the same type. And like Tuples, Arrays are always of a fixed length. Arrays in Rust are similar to Lists in Python as they use the square brackets [] in its definition and we can access their values by providing the index inside the brackets.
```rust
let number = [1, 2, 3, 4];
println!("The second number is {}", number[1])
```
You can provide the type of an Array like this
>[type; size]

```rust
let a: [u8; 5] = [1, 3, 4, 5, 6];
```
Also we can initialize an Array like this
> let array = [value; size];

```rust
let a = [10; 3]; // An array of size 3 of 10 value
``` 
Rust won't let you use indexes past the size-1 of the Array. For example, the following will error out:
```rust
let hours = [1; 24];
println!("{}", hours[25])
```

In the next article, we will continue our discussion about the Rust basics, function and flow control. See you then 👋