DEV Community

Cover image for Variables and Data types in Rust: A simplified approach.
Aliyu Adeniji
Aliyu Adeniji

Posted on • Originally published at Medium

Variables and Data types in Rust: A simplified approach.

Introduction

Rust is a programming language that is well known for its type-safety and performance. Variables and data types are integral parts of all programming languages, hence, understanding variables and data types is essential for any Rust developer. This article explores how Rust handles variable declarations, immutability, control flow, and the variety of built-in data types, providing a solid foundation for building efficient programs.

What are Rust Variables?

Variables are named storage locations in a computer memory; they hold values that are used for the overall functioning of computer programs. The value that a variable hold can be a number, strings of text, or other complex data.

Variables in Rust are immutable by default, meaning that you cannot change the value of a declared variable at a later time, even you cannot mistakenly change the value of a declared variable, this gives Rust an advantage over some other programming languages, this type of immutability improves the safety and concurrency of Rust programs.

In the code block below, we try to change the value of the variable b but when you try to run the code, you will get a compiler error indicating that b is an immutable variable.

 let b = 9;
    println!("The value of b is: {b}");
Enter fullscreen mode Exit fullscreen mode

If you want to change a value of a variable in Rust, you have to explicitly tell Rust that you want to change the value of the variable by declaring the variable to be mutable.

This mutability is also useful in programs that need to dynamically change values of a variable, depending on user’s input or some other scenario.

Check the code block below and see how to make a variable mutable in Rust.

 let mut b = 8;
    println!("The value of b is: {b}");
    b = 39;
    println!("The value of b is: {b}");
Enter fullscreen mode Exit fullscreen mode

Try to run the code block, you will get the two values printed, and in the second print value, the new value of b will be 39. This means that you have been able to change the value of the variable b successfully.

What are Constant Variables in Rust?

Like every other programming language, constants in Rust are always immutable, and in contrasts to variables, you cannot change the values of constants with the mut keyword.

This immutability property of constants is useful for programs where you do not expect the values of a constant to change in anyway.

To declare a constant in Rust, you use the const keyword, and a distinct property of constants in Rust is that you must annotate the data type of the const.

const NUM_OF_ATTENDEES: u32 = 100;
Enter fullscreen mode Exit fullscreen mode

Constants also can be declared anywhere in your code and can be referenced in any part of your code; this makes them globally accessible opposite to variables that are not globally accessible.

One last major difference between constants and variables is that constants can only be set to a const expression, and not the result of a value that can only be computed at run time, that is, before you can declare a constant and for such a constant to be valid, the value of the constant must be known at compile time.

Further explanation, constants cannot be set to depend on input or output of a program.

Check for how to declare a valid const below.

const MAX_POINTS: u32 = 500;
Enter fullscreen mode Exit fullscreen mode

An example of an invalid constant declaration is the one blow which can only be evaluated at runtime.

const RANDOM_USERS: u32 = get_random_users(); // Invalid, as `get_random_users()` is computed at runtime
Enter fullscreen mode Exit fullscreen mode

What is shadowing in Rust?

In a situation where you want to reuse a variable name for some other purpose, you can use shadowing to do this, shadowing allows you to shadow a variable by another second variable.

For example, in the code block below, we can make a shadow of the initial variable by setting it to another value that can also be used, in this way, the compiler will always take note of the last value that the variable is set to and that is what it will actually make use of.

let initial = 20;
let initial = 20 + 1;
println!("The value of initial is: {initial}"):
Enter fullscreen mode Exit fullscreen mode

When you run the code above, what you will get on your terminal is 21 which is the value of the shadowing of the initial variable.

Another usage of Shadowing is when you want to use a variable in a scope that is different from the initial scope of the variable, this will create a shadow copy of the variable and isolate it from the initial scope, thereby maintaining the immutability of the base variable.

Look at how this is done below using the combination of the variable in the previous example and a new variable scope.

let initial = 20;
let initial = 20 +1;
{   let initial = initial *30;
    println!("The value of the initial variable has been updated in this scope to: {initial}");
}   
println!("The value of initial is: {initial}");
Enter fullscreen mode Exit fullscreen mode

When you run the code block above, you will get two values, which are the value of the initial variable in the inner scope created, and also the last value of the initial variable that was declared immediately before the scope.

Another usage of shadowing is that it can be used to change the data type of a variable to another type without expressly writing long lines of code to do that.

Here is a common example of changing a variable data type by shadowing the variable.

let x = " ";      
let x = x.len(); 
Enter fullscreen mode Exit fullscreen mode

The first variable above will return a string while the second variable will return an integer data type.

What are Rust Data types?

Rust is a statically typed programming language; this makes it mandatory for you to specify the data types you are working with before your programs can be compiled successfully.

This is one of the ways that Rust ensures that there are no conflicts with the data that you get as an output, imagine a programing language that takes in a string data type, and after compilation, it returns an unsigned integer u32. This can lead to issues like memory leak and fake data output, Rust is designed to prevent this.

There are two major data types in Rust, and they are:

  1. Scalar Types
  2. Compound Types

Scalar type data are those that represent a single vale. There are four Scalar types of data types in Rust:

  • Integers
  • floating-point
  • Booleans
  • Characters

Integer Types

An integer is a number that does not have a decimal or fraction, it is a whole number that can either be a positive number, a negative number, or even a zero number.

Rust integers can either be a signed or unsigned integer, and they have different number of bits they occupy.

A signed integer indicates the possibility of the integer to be of a negative value, in that case, there must be a sign that indicates that, while an unsigned integer indicates that the number will always be a positive value.

An Arch integer is based on the types of a computer architecture, and they are either 32-bit size or 64-bit size.

The table below shows the types and sizes of integers in Rust.

Length Signed Unsigned
8-bit i8 u8
16-bit i16 u16
32-bit i32 u32
64-bit i64 u64
128-bit i128 u128
arch isize usize

Floating-Point Types

The floating-point numbers in Rust are numbers with decimals and they are two types: the f32 and f64 . The default floating-point type is f64, and any decimal number in the Rust programming are always in f64 bits, unless otherwise specified.

Look at the examples below, in the first variable, the floating type is not specified, and by default it is f64 while in the second example, the floating type is indicated to be f32.

let variable_one = 2.0;   //f64

let variable_two: f32 = 7.5;   //f32 
Enter fullscreen mode Exit fullscreen mode

Boolean Types

There are no other ways to denote Boolean types in Rust except as either true or false . These are the default Boolean types that are specified with the bool keyword. The example below is an illustration of how to use the Boolean types in Rust.

let is_true: bool = true;

let is_false: bool = false;
Enter fullscreen mode Exit fullscreen mode

Character Type

The character type in rust is simply declared by setting the char variable in quotation. The code block below illustrates the different ways of declaring the character types in Rust.

let a = 'a';
let b: char = 'B';
let smiling_face = '😊';
Enter fullscreen mode Exit fullscreen mode

Compound Types

As the name suggests, compound types are used to group multiple value items into a single type. The two compound types in Rust are: tuples and arrays.

Tuple Type

The tuple type is used to group values of different data types into one, to create a tuple, you must declare the data types of each element in the tuple, separated by a comma.

Tuples have fixed lengths, thus, as soon as they are declared, they cannot change in size in whatever way. The example below is how to declare a tuple in Rust.

let tuple_data:(i32, f64, u8, char) = (-50, 5.5, 1, 'A');
Enter fullscreen mode Exit fullscreen mode

Array Type

Arrays in Rust are also collections of multiple values into a single array, in Rust, all the elements of an array must be of the same data types.

Arrays in Rust have fixed lengths, as such, you cannot modify the size of an array, to have such a collection of arrays that can be modified, you can use a vector collection instead.

The example below is how to create an array in Rust.

let array = [1, 2, 3, 4, 5];
Enter fullscreen mode Exit fullscreen mode

Another way to initialize an array in Rust is as shown in the code snippet below, but this time around, you want to initiate an array with the same values all through.

let array = [7; 6];
Enter fullscreen mode Exit fullscreen mode

To access the elements in a Rust array, you use indexing method by indicating the index of an element you want to access as shown below.

let new_array = [4, 5, 6, 7, 9, 0];

let first_element = new_array[0];
let second_element = new_array[1];
Enter fullscreen mode Exit fullscreen mode

When you run the program to print the first and second elements in the array above, you will get the results according to the index specified.

Lastly on Arays, in Rust, you cannot access and invalid Array element, this is one of the memory safety provisions in Rust, a program where you try to access an invalid array element will always panic and will not run until you resolve the error indicated by the Rust engine.

Conclusion

In Rust, variables and data types are the basics for safe, efficient programming. In this article, we leant about the various ways to work with variables and create standard programs. With all these safety measures in Rust, it prevents common programming errors at compile time.

Understanding primitive types (integers, floats, Booleans) and compound types (tuples, arrays, strings) prepares you for advanced concepts.

Top comments (0)